Layui表格编辑需在edit事件首行调用e.preventDefault()实现事前拦截,校验失败时手动恢复输入框值并用table.updateCell更新,避免数据不一致。
edit 事件里不能只监听,必须 e.preventDefault() 拦住默认写入
单元格编辑后失焦(比如按 tab 或点其他地方),layui 默认会立刻把新值写进 dom 和数据源。验证不是“事后检查”,而是“事前拦截”——不拦住,值已经落库,再校验就晚了。
- 必须在
table.on('edit(test)', ...)回调里第一行就写e.preventDefault() -
e.value是用户刚输的字符串,e.oldValue是原始值,别混淆 - 校验失败时,得手动恢复输入框内容:
e.tr.find("td[data-field='"+e.field+"'] input").val(e.oldValue) - 不恢复会导致表格显示和内部数据不一致,比如用户输错后没提示、还留着非法值
数字/邮箱/非空这类常见验证,正则要覆盖边界情况
内置没有验证规则,全靠自己写逻辑。但容易漏掉细节:空格没 trim、负号被忽略、邮箱里允许中文域名、小数点后多于两位等。
- 非空判断别用
!e.value,应写!e.value.trim() - 数字校验别直接
isNaN(+e.value),因为"123 "会被转成123,但用户可能真想输带空格的字符串 - 邮箱正则至少包含
^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$,否则user@sub.example.com会失败 - 验证通过后,要用
table.updateCell(e.id, e.field, e.value.trim())显式更新,而不是改e.data[e.field]—— 那只是快照,不生效
失焦验证失效?先查 e.id 是否对得上真实主键
表格每行的 e.id 默认是自增数字,但如果你在 cols 里写了 id: 'uid',那 e.id 就是该行 uid 字段的值。如果数据源里没这个字段,或字段名拼错,updateCell 就找不到目标行。
- 检查
table.render()的cols配置,确认是否声明了id: 'xxx' - 打印
console.log(e.id, e.data),看e.id值是否和e.data中对应字段一致 - 避免重复绑定
table.on('edit(...)', ...),重载表格后没清理旧监听,会导致一次编辑触发多次验证 - 动态重绘表格(如
table.reload())后,必须重新绑定 edit 事件,且只绑一次
想统一处理多个字段?别逐个写 lay-verify,用 edit 事件 + 字段映射表
十几个可编辑列,每个都写独立验证逻辑太冗余。可以预先定义一个验证规则映射:
const fieldRules = {
price: (v) => /^(\d+\.?\d{0,2}|\.?\d{1,2})$/.test(v.trim()) || '请输入最多两位小数',
email: (v) => /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(v.trim()) || '邮箱格式错误',
name: (v) => v.trim().length >= 2 || '姓名至少2个字符'
};
然后在 edit 回调里复用:
table.on('edit(test)', function(e){
e.preventDefault();
const rule = fieldRules[e.field];
if (rule) {
const msg = rule(e.value);
if (msg !== true) {
layer.msg(msg, {icon: 5});
e.tr.find("td[data-field='"+e.field+"'] input").val(e.oldValue);
return;
}
}
table.updateCell(e.id, e.field, e.value.trim());
});
真正难的不是写正则,而是每次 e.id 和后端返回的数据结构不一致,或者忘记 trim() 导致前后端校验结果不一致——这种问题往往要翻好几层日志才能定位。











