资讯详情

layui下拉框搜索词自动清空:原理、方案与远程搜索实践

📅 2026/9/23 4:36:24 | 华诺云谱 👁 阅读
layui下拉框搜索词自动清空:原理、方案与远程搜索实践
1. 先说你遇到的“清空”它到底是个需求还是个坑我在给一个后台管理系统做审批人选择器时用 layui 的下拉框加lay-search做了个可搜索下拉功能跑通以后测试提了个需求每次点开下拉框搜索框里还留着上次输入的“张”之类的关键字列表被过滤得只剩几条能不能点开的时候自动把搜索框的值清空让所有选项都露出来。这句话如果你在搜索引擎里拆开看会发现两种完全不同的诉求被混在一起了。第一种就是要实现上面这个“点击展开时自动清空搜索词”的效果第二种则是有人发现form.render(select)重新渲染下拉后搜索框的值不见了想保留却留不住。这两种问题表象都是“清空搜索框的值”但解决思路完全相反一个是要主动清一个是想别清。为了避免你调试一晚上才发现方向错了我先把两种场景列个对比场景表现本质A. 主动清空需求上次搜索关键词留在输入框里列表被过滤要监听展开事件手动清空并恢复列表B. 被动清空 Bug选中值后重新渲染搜索框内容丢失渲染机制导致需要避开或回填这篇文章主要解决场景 A但场景 B 也会讲透因为实现 A 时你会发现layui 的搜索框和选中值显示共用了同一个 input绕不开 B 的连带问题。先说复现环境。一个普通的下拉搜索写法select iddept lay-filterdept lay-search option value请选择部门/option option value1技术部/option option value2产品部/option option value3运营部/option /selectlayui.use([form], function () { var form layui.form; form.render(); });此时你打开页面点一下下拉框输入“技”列表过滤出“技术部”。然后你把下拉关掉再点开搜索框里还是“技”列表还是只剩一项。如果项目里用户是几十个部门这个体验倒还能忍但如果换成几千人的审批人选择器每次点开都要先手动删掉上次的关键字那就没法用了。所以你要做的就是在下拉面板展开的那一刻把搜索框里的残留关键字清掉同时把被过滤掉的选项全部恢复显示。2. 为什么直接清空 input 不够先看懂 layui 下拉搜索的 DOM 结构明明只是一句$(#dept).val()的事为什么网上搜出来的方案五花八门因为#dept这个select在你执行form.render()之后已经不是页面上那个可见元素了。layui 的 select 渲染机制是把原来的select隐藏display:none在旁边生成一套自定义的 div 结构。加lay-search之后渲染结果大致是这样的select iddept lay-search lay-filterdept styledisplay:none option value请选择部门/option option value1技术部/option /select div classlayui-form-select div classlayui-select-title input typetext placeholder输入关键字搜索 classlayui-input layui-unselect i classlayui-edge/i /div dl classlayui-anim layui-anim-upbit dd classlayui-select-tips请选择部门/dd dd lay-value1技术部/dd dd lay-value2产品部/dd /dl /div注意看真正的搜索框其实是.layui-select-title里的那个input它同时承担两个职责显示当前选中值的文本以及作为搜索关键字输入框。这个设计是后面所有坑的根源。当你选中“技术部”后这个 input 的值是“技术部”。你点开下拉框想搜索别的部门时在同一个 input 里输入“产”原来的“技术部”就被替换成了“产”。此时隐藏的select里的值仍然是 1也就是说选中值其实没丢只是显示层的 input 被搜索词覆盖了。很多人以为选中值丢了就是被这个表象骗了。明白了这一层你就知道为什么简单清空会有副作用$(.layui-select-title input).val(); // 看起来清空了如果你当前有选中值这一句会把“技术部”三个字也抹掉。面板收起后下拉框显示为空但表单提交时select隐藏值还是 1用户看到的是“明明没选任何东西提交却带上了技术部的 id”这种不一致比搜索词残留更可怕。另外还有一个版本差异得提一句。layui 在 2.6 之前搜索词在面板收起再打开后是不保留的也就是天然满足“点击时清空”这个需求。但从某个版本开始搜索词的记忆行为变了重新打开面板会保留上次输入的关键字。所以网上老方案在新版本上直接失效你照着抄会发现根本不生效先确认一下自己用的 layui 版本别在这上面浪费时间。3. 实现“点击展开自动清空搜索词”的三套方案知道了 DOM 结构方案就好设计了。核心思路是在下拉框展开前把搜索框 input 的值清掉并触发 layui 内部的过滤逻辑让所有选项恢复显示。我给三种写法从简单到严谨按需选用。3.1 方案一focus 事件 setTimeout 清空这是最快能跑通的写法。点击下拉框时搜索框 input 会获得焦点此时在 focus 事件里做清空$(document).on(focus, .layui-select-title input, function () { var _this this; setTimeout(function () { if ($(_this).val() ! ) { $(_this).val(); $(_this).trigger(input); } }, 0); });这里有两个关键细节。第一必须用setTimeout包一层因为点击 input 时先触发 focus然后 layui 才展开面板并执行自己的搜索词回填逻辑如果不延迟到下一个事件循环你这边刚清空layui 那边又把记忆的关键字填回来了等于白干。第二清空后要手动trigger(input)layui 监听的是 input 事件来判断是否过滤选项只改 value 不触发事件列表不会恢复。这个方案能用但副作用很直接如果你有选中值input 里显示的“技术部”同样会被清掉。适合下拉框只用来做筛选条件、不需要回显选中文本的场景。3.2 方案二blur 时回显选中文本解决“选中值显示消失”针对方案一的副作用我们在 input 失去焦点时把选中文本补回来。失去焦点意味着两种情况用户选了一个新选项或者用户点到了页面其他地方关闭了面板。如果是第一种layui 会把新选中文本写进 input我们不需要管如果是第二种我们要把原来的选中文本恢复回去。判断依据就是 input 的值如果它为空并且隐藏的 select 里有选中的 option就把 option 的文本写回 input$(document).on(blur, .layui-select-title input, function () { var $input $(this); var $selectBox $input.closest(.layui-form-select); var $select $selectBox.prev(select); var selectedText $select.find(option:selected).text(); if ($input.val() selectedText) { $input.val(selectedText); } });假设你选中了“技术部”点开下拉focus 处理把 input 清空此时隐藏 select 的值仍然是 1。你在列表里看到全部部门但没做任何选择直接点页面空白处关闭面板blur 触发后发现 input 是空的就把“技术部”重新填回去界面恢复正常。如果你在清空后输入“产”过滤出“产品部”并选中blur 时 input 的值是“产品部”不是空所以不会被覆盖。逻辑上闭环了。提示$selectBox.prev(select)依赖 DOM 结构顺序如果你对某些下拉框做过包裹或者调整了 DOM 位置要改成更稳妥的方式比如在事件监听前用data把 select 的 id 存到容器上。3.3 方案三按需开关注入只处理指定的下拉框前两个方案都是全局监听页面里所有带lay-search的下拉框都会生效。实际项目里往往只有少数几个下拉框需要这种“每次展开清空”的行为其他下拉框可能希望保留搜索词方便连续操作。所以我在这个方案里加了一个开关属性>select idapprover lay-search>$(document).on(focus, .layui-select-title input, function () { var $input $(this); var $selectBox $input.closest(.layui-form-select); var $select $selectBox.prev(select); if ($select.attr(data-clear-search) ! true) { return; } setTimeout(function () { if ($input.val() ! ) { $input.val(); $input.trigger(input); } }, 0); }); $(document).on(blur, .layui-select-title input, function () { var $input $(this); var $selectBox $input.closest(.layui-form-select); var $select $selectBox.prev(select); if ($select.attr(data-clear-search) ! true) { return; } var selectedText $select.find(option:selected).text(); if ($input.val() selectedText) { $input.val(selectedText); } });判断条件写在事件回调开头不开这个开关的下拉框完全不受影响。我在项目里把这段逻辑封装成了一个initClearSearch()函数所有需要该行为的 select 加一个属性就行业务代码零侵入。3.4 三套方案怎么选方案实现成本选中文本回显适用范围方案一最低不清空选中文本筛选条件型下拉框方案二中等自动回显表单字段型下拉框方案三中等自动回显多下拉框混用的大型页面我的建议是直接用方案三它只是比方案二多了一个属性判断成本几乎可以忽略但能给后续维护省下很多沟通成本——你不需要跟接手的人解释“为什么所有下拉框搜索词都被清掉了”。4. 清空之后还有三个连带坑一次性说清方案跑通只是第一步。实际用起来你会发现清空了搜索词问题一波接一波。4.1 placeholder 不显示的坑加了lay-search后未选中任何项时标题栏 input 是空的但默认情况下它不会显示“请选择部门”这样的提示文字看起来像个残缺的输入框。layui 的官方支持是给lay-search属性直接赋值作为 placeholderselect lay-search输入部门名称搜索 lay-filterdept这是最省事的写法赋值会被渲染成搜索框 input 的 placeholder。如果你需要动态换提示文字也可以用form.render之后手动给 input 设置 placeholder 属性但要注意渲染时机否则会被覆盖。4.2 选中后重新点开搜索框又被清掉了但列表没有恢复这个是方案一容易踩的只清了 input 的 value没有触发 input 事件layui 内部的过滤状态还停留在上一次。表现就是 input 空了但列表里还是只有“技术部”一个选项。所以前面代码里我特意写了$(_this).trigger(input)这一句才是真正让 layui 重置过滤列表的关键。你如果自己写过类似功能清空后一定要记得触发这个事件否则会以为方案失效。4.3 动态更新选项后原事件失效如果你的下拉框选项是动态加载的比如先通过 AJAX 拿到数据再往 select 里塞 option最后调form.render(select)此时 DOM 被整个重建之前绑定在下拉框节点上的事件如果绑的是具体元素就会丢失。我上面的写法用的是$(document).on(...)事件委托所以不受重建影响这也是我推荐用委托而不是直接绑.layui-select-title input的原因。另外一个动态渲染的坑是form.render(select)会让下拉面板收起如果用户正在输入搜索词你动态把选项更新了面板会突然关闭体验非常糟。这不属于清空问题但和动态数据强相关下一节我会展开讲。5. 从下拉搜索到流程审批远程搜索的完整实践热搜词里有一串“用 layui 设计流程审批”审批人选择是流程审批里最典型的下拉搜索场景。前面静态下拉框的做法在审批人列表只有几十条时没问题但公司上千人时把所有用户一次性渲染进下拉框页面卡顿不说搜索起来也不流畅。这种场景更合理的做法是远程搜索输入关键字向后端发请求返回匹配的人员。5.1 远程搜索的基本思路不要把远程搜索做成“改 select 的 option 再 form.render”那样每次输入都会重建 DOM、收起面板根本没法连续输入。正确的做法是直接操作已经渲染出来的dl列表只替换里面的dd选项保持面板始终展开。var searchTimer null; $(document).on(input, .layui-select-title input, function () { var $input $(this); var $selectBox $input.closest(.layui-form-select); var $select $selectBox.prev(select); var keyword $.trim($input.val()); // 仅处理开启了远程搜索的 select if ($select.attr(data-remote-search) ! true) { return; } clearTimeout(searchTimer); searchTimer setTimeout(function () { $.get(/api/user/search, { keyword: keyword }, function (res) { if (res.code ! 0) return; var $dl $selectBox.find(dl); // 保留第一个 tips 节点清空其余选项 $dl.find(dd).not(.layui-select-tips).remove(); if (res.data.length 0) { $dl.append(dd classlayui-disabled无匹配用户/dd); return; } res.data.forEach(function (item) { $dl.append(dd lay-value item.id item.name item.dept /dd); }); // 重新绑定 dd 的点击行为 layui.form.render(select); }); }, 300); });这里同样要注意form.render(select)的副作用它会重建整个下拉框 DOM把面板收起。上面这段代码我刻意不去调用它而是手动维护dl里的dd。但代价是新插入的dd没有 layui 帮你绑定的选择事件所以点击新选项不会生效。解决方法是每次更新完dd后还是得调一次form.render(select)它在重建的同时会重新绑定事件。面板收起的问题怎么规避实测下来的做法是在form.render之前记录当前下拉框渲染完成后再手动找到新的dd列表并重新展开面板。具体来说渲染后可通过$select.next(.layui-form-select).addClass(layui-form-selected)把面板重新展开。虽然会有一瞬间的闪烁但比完全不能输入强。5.2 后台接口与数据表设计配合远程搜索后端接口一般返回人员 id、姓名、部门这些字段。数据表最简单的设计可以是这样CREATE TABLE sys_user ( id INT PRIMARY KEY AUTO_INCREMENT, name VARCHAR(50) NOT NULL, dept VARCHAR(50), status TINYINT DEFAULT 1, INDEX idx_name (name) ) COMMENT 用户表; CREATE TABLE flow_approval_node ( id INT PRIMARY KEY AUTO_INCREMENT, flow_id INT NOT NULL, node_name VARCHAR(50) NOT NULL, approver_id INT NOT NULL, sort_no INT DEFAULT 0, INDEX idx_flow (flow_id) ) COMMENT 审批流程节点表;查询接口的核心 SQL 就是按姓名模糊匹配SELECT id, name, dept FROM sys_user WHERE name LIKE CONCAT(%, #{keyword}, %) AND status 1 LIMIT 20;人员多了以后一定要限制返回条数否则搜索接口本身也会变慢。前端拿到 20 条渲染成dd对于审批人选择场景足够了。选中后再把approver_id写入对应的审批节点表这就是一个完整的审批人选择链路。5.3 远程搜索和前面清空逻辑的配合远程搜索场景下每次点击展开下拉框同样会遇到“上次搜索词残留”的问题。此时前面方案三的 focus 清空逻辑依然有效但清空后还要让列表恢复成默认的推荐列表而不是空列表。所以清空 input 后除了trigger(input)如果该项目之前是远程搜索的还要额外判断关键字是否为空为空就加载默认列表。if ($input.val() ) { loadDefaultApproverList($selectBox); }这个细节很容易被忽略很多人发现清空关键字后列表是白的以为代码写错了实际上是没有走“空关键字加载默认列表”的分支。6. 遇到“搜索框值不对”时的排查顺序最后总结一下我自己的排查习惯。下拉框搜索值出问题原因通常藏在下面几个环节按顺序查最快先确认 layui 版本。2.6 前后对搜索词记忆行为有差异老版本的“自然清空”不代表你代码正确新版本可能就是这个差异导致你的方案失效。F12 看一下渲染后的 DOM 结构确认.layui-select-title input的 class 是否和你选择器匹配。有些项目自定义了 layui 皮肤class 会被覆盖。检查代码里有没有在change回调中调用form.render(select)。这是最常见的“搜索框被清空”Bug 来源只要 render 就会重建 DOM清空搜索框是必然结果。检查 input 事件链。如果你或者第三方组件在 input 上绑了其他事件且调用了stopPropagation或preventDefaultlayui 的过滤逻辑可能被中断表现为搜索框值被清了但列表没恢复。页面上有多个下拉框时一定通过.closest(.layui-form-select)和prev(select)定位不要用全局的$(.layui-select-title input)否则操作了一个下拉框其他下拉框也会跟着遭殃。拿我们项目举例最终我选了方案三并把 focus 清空、blur 回显、远程搜索封装成了一个模块所有审批人下拉框统一走这个模块。后续测试再提“点开搜索框还留上次关键字”的需求我只需要给对应 select 加一个>
📝

华诺云谱内容团队

资深建站顾问 · 行业研究员

10年+企业数字化服务经验,专注智能建站、SEO优化与品牌营销,持续输出建站技巧、行业洞察与营销干货,已帮助5000+企业实现数字化增长。

你可能需要的服务

订阅华诺云谱资讯周报

每周一封,精选建站技巧、SEO与营销干货,直达邮箱。已有 8,000+ 企业主订阅,助你少走弯路。