Layui switch 事件无法用 preventDefault 拦截,需在 form.on('switch') 中用 confirm 确认后手动翻转状态并调 form.render;禁用应设 disabled 属性并重渲染;移动端需加 data-clicking 防连点。

form.on('switch()') 里不能用 event.preventDefault() 拦截
因为 Layui 的 form.on('switch(filter)') 是在开关状态已经切换完成之后才触发的,不是“点击瞬间”或“切换前”的钩子。你写 event.preventDefault() 完全无效,DOM 和内部状态早就改完了。
必须手动回滚 + 弹 confirm 控制真实状态
想实现“点一下先问、再决定是否真切”,就得靠视觉还原和主动控制:
- 在
form.on('switch(filter)')回调开头立刻调layer.confirm() - 用户点「确定」后,用
$(data.elem).prop('checked', !data.elem.checked)把开关状态翻回去(因为 Layui 已经把它切过去了) - 再手动发请求、更新 UI 或数据库;成功后再调
form.render('checkbox')同步 UI - 用户点「取消」时,也得用
$(data.elem).prop('checked', data.elem.checked)强制回滚——否则视觉和 DOM 不一致,下一次点击逻辑就乱了
禁用 switch 本身比防连点更可靠
如果业务允许,直接禁用比拦截点击更干净:
- 给原始
<input type="checkbox">加disabled属性 - 紧接着必须调
form.render('checkbox'),否则 UI 不灰显、事件仍可能被触发 - 别只加
layui-btn-disabled类或 CSSpointer-events: none——Layui 重绘时会清掉这些 - 禁用后提交表单,
form.serialize()仍会包含该字段值,如需过滤,得在form.on('submit')里手动delete data.fieldName
移动端 touchstart 阶段就要锁住
安卓 WebView 或旧 iOS 有 300ms 延迟,用户快速连点可能触发两次 form.on('switch())。解决方法:
- 在绑定 switch 之前,给对应元素加一个
data-clicking="false" - 回调开头判断:
if ($(data.elem).closest('td').data('clicking')) return; - 然后立刻设为
true,confirm 结束后在 yes/cancel 里都设回false - 这个标记要挂到行级容器(比如
<tr> 或 <code><td>)上,避免跨行误锁 真正容易被忽略的是:confirm 弹窗的异步性会让状态管理变脆弱。哪怕只漏掉一个 cancel 分支的回滚,或者少一次 <code>form.render('checkbox'),后续点击就会出现“UI 显示开、实际关”或“点不动但数据已变”的错位。


















