layui 的表单提交按钮上写 lay-submit 和 lay-filter,点击后触发 form.on('submit(filter名)') 回调。这个机制我用了三年,踩过最大的坑是:回调里 return false 会阻止表单默认提交,但如果你忘了写,页面直接刷新,弹窗都没来得及弹。
第一次接触 layui 事件是 2019 年做一个后台管理系统。当时用 jQuery 写 $('#btn').click(),结果表格里的按钮是动态渲染的,绑不上。后来翻文档才知道 layui 的表格工具栏事件得用 table.on('tool(test)'),那个 test 是 table.render() 里 id 对应的值。改完代码,控制台终于打印出 obj.data,里面装着当前行的所有字段。那一刻感觉 layui 的设计挺贼——它把事件监听挂在了模块内部,而不是 DOM 上。
模块化事件是 layui 的核心逻辑。每个组件(form、table、laypage、upload)都有自己的事件系统,统一用 on 方法监听。比如分页组件 laypage.render() 里的 jump 回调,每次翻页都会执行,参数是当前页码和每页条数。我见过有人用 laypage 做无限滚动,结果 jump 里又调了一次 render,死循环。其实 jump 只负责拿页码去请求数据,重绘交给 table.reload 就行。
有个细节值得说:layui 的事件回调里经常出现 obj 和 data 两个参数。比如 table.on('edit(test)') 的 obj 包含 value(修改后的值)、field(字段名)、data(整行数据)。我同事曾经把 obj.value 写成 obj.data.value,调试了半小时。这种命名习惯在 layui 里很统一,但第一次用容易混。
事件冒泡在 layui 里基本被屏蔽了。你给表格行绑定 click,再给行内按钮绑定 click,点按钮时行的事件不会触发。因为 layui 的表格渲染用的是 div 模拟 table,事件委托在 layui-table-body 上。想阻止默认行为?在回调里 return false 就行,但只对 form 的 submit 和 table 的 tool 有效。其他事件得用 event.stopPropagation(),不过 layui 文档没提这个,我是看源码发现的。
动态元素的事件绑定是个老问题。比如用 layer.open 弹出一个表单,里面的按钮用 lay-submit 没问题,但如果你用 append 往弹窗里加一个普通按钮,再 $('#newBtn').click() 就失效。正确做法是 $(document).on('click', '#newBtn', function(){ })。layui 自己的组件都走 on 机制,所以不受影响。我现在的习惯是:只要元素是 JS 生成的,一律用事件委托。
最后说个冷门事件:layui.onevent 可以自定义模块事件。比如你写了个 myMod 模块,想让它支持 myMod.on('custom(filter)'),就在模块里调 layui.onevent('myMod', 'custom', callback)。这个 API 几乎没人用,但看 layui 源码时发现 table 和 form 内部就是这么注册的。理解这一点,再去看 form.on('submit') 为什么能生效,就通透了——无非是模块初始化时把事件挂到了 layui.event 的缓存里。