lay-search仅支持搜索过滤,不保存用户输入值;需监听input事件动态添加option、同步更新select元素及隐藏域,确保提交时获取准确值。
lay-search 是基础,但不能直接保存新输入值
layui 的 lay-search 属性确实能让 select 显示搜索框、支持输入过滤,但它本质仍是原生 select 行为:用户输完内容后,若没点击任何 option,表单提交时该字段值为空或保持上一个选中值——**新输入的文字不会自动成为有效选项,也不会被提交**。
这是最常被误解的点。很多人加了 lay-search 就以为“可输入”等于“可提交”,结果后端收不到用户手输的内容。
-
lay-search只触发过滤逻辑,不修改 DOM 结构,也不监听input事件 - 用户输入后直接失焦(比如点别处或按回车),
select值仍为上次选中的value,或空字符串 - 必须手动捕获输入内容,并动态插入
option或同步到隐藏字段
监听 input 事件 + 动态追加 option 是最简可行方案
核心思路是:让用户在搜索框里输入时,实时判断是否已有匹配项;没有就临时加一条 option,并确保它能被 form.on('select(xxx)') 捕获。
关键代码要点:
- 用
$('body').on('input', '.layui-select-title input', ...)监听所有 layui select 的搜索输入(避免重复绑定) - 通过
$(this).closest('.layui-form-select').find('dl')定位对应下拉菜单容器 - 检查
dl.find('dd[lay-value="' + val + '"]').length === 0,避免重复添加 - 插入新
dd时带上lay-value和文本,例如:<dd lay-value="自定义值">自定义值</dd> - 用户点击该
dd后,再用form.render('select')刷新,否则新选项不生效
注意:新 option 必须同时写入真实 select 元素,否则表单序列化时拿不到——仅往 dl 里加 dd 不够。
form.on('select(xxx)') 回调里要同步更新 select 的 value 和 option
用户从下拉列表中选择(包括你刚动态加的那条),form.on('select(xxx)') 会触发,但此时 data.value 是 lay-value,而真实 select 的 value 可能还没变。必须显式操作 DOM 才能确保提交值正确。
- 在回调中执行
$('#xxx').val(data.value),强制设置真实select的 value - 如果该值尚不存在于原始
option中,需同步追加:$('#xxx').append('<option value="' + data.value + '" selected>' + data.value + '</option>') - 最后调用
form.render('select', 'xxx')(第二个参数指定容器 ID,提升性能) - 否则,多次选择后可能出现值错乱、提交空值、或浏览器缓存旧选项等问题
实际提交前,建议用 hidden input 备份最终值
哪怕上面几步都做了,Layui 的 form.serialize() 仍可能漏掉动态新增的选项,尤其当页面有多个 select 或存在异步渲染时。更稳妥的方式是:用一个隐藏域始终记录当前最终值。
- 在输入或选择时,统一更新
<input type="hidden" name="xxx_real" id="xxx_real"> - 监听所有变更入口:input 事件(输完回车)、select 事件(点选项)、blur 事件(输完直接离开)
- 提交前校验
$('#xxx_real').val()是否非空,优先以它为准 - 这样既绕过 layui 表单序列化的不确定性,也方便后端统一接收字段,不用区分“是选的还是输的”
真正容易被忽略的不是怎么加功能,而是怎么让这个“自由输入”的值,在表单提交那一刻,稳稳地进到后端数据库里——中间任何一环没串起来,用户就会觉得“我明明输了,怎么没保存?”


















