必须用 form.verify() 注册同步规则,再通过 form.on('submit') 拦截提交并手动发起异步请求,校验通过后调用 data.form.submit() 触发原生提交,避免死循环。

lay-verify 怎么绑定自定义异步校验函数
不能直接在 lay-verify 属性里写异步逻辑,Layui 的内置验证是同步的。必须用 form.verify() 注册一个带 Ajax 的规则,再在表单元素上通过 lay-verify="yourRuleName" 引用。
- 异步校验必须手动调用
layui.form().verify()或触发form.on('submit')时由框架自动调用 - 注册的函数接收两个参数:
value(当前输入值)和item(DOM 元素),返回undefined表示通过,返回字符串表示错误提示 - 注意:函数体内部不能直接 return 错误信息,因为 Ajax 是异步的 —— 必须用
return false阻止默认提交,并在回调里用form.msg()或操作 DOM 显示提示
为什么 form.verify() 里的异步函数不生效
因为 form.verify() 期望的是同步返回,你放个 $.ajax() 进去,函数立刻执行完并返回 undefined,校验就“通过”了,根本等不到请求回来。
- 真实场景中,常见错误是这样写:
form.verify({ checkUser: function(value) { $.get('/api/check', {u: value}, ...) } })—— 这毫无校验效果 - 正确做法是:把表单提交拦截下来,在回调里手动判断并调用
form.msg()或layer.msg()提示,再决定是否允许提交 - Layui 2.8+ 支持
form.on('submit')中用return false阻止提交,这是唯一可控的时机
实际可运行的异步校验写法(含防重复提交)
核心思路:禁用提交按钮 → 发起请求 → 根据响应决定是否恢复按钮或跳转。
form.on('submit(login)', function(data){
var btn = $(this).find('button[type="submit"]');
btn.prop('disabled', true).text('校验中...');
$.post('/api/check-username', { username: data.field.username }, function(res){
if(res.code === 0) {
// 校验通过,继续提交
layer.msg('用户名可用');
// 注意:这里不能直接 submit(),会死循环,应改用原生 form.submit()
data.form.submit();
} else {
layer.msg(res.msg || '用户名已存在');
btn.prop('disabled', false).text('立即登录');
// 手动聚焦到出错字段
$('input[name="username"]').focus();
}
}).fail(function(){
layer.msg('网络异常');
btn.prop('disabled', false).text('立即登录');
});
return false; // 阻止默认提交
});
- 不要依赖
lay-verify自动触发异步,它压根不支持 -
data.form.submit()是原生 DOM 表单对象,避免再次触发 layui 的 submit 监听 - 务必加按钮禁用和文字反馈,否则用户可能连点多次,后端收到重复请求
- 服务端返回格式建议统一为
{code: 0, msg: ''},前端只关心code
兼容性与性能注意点
Layui 本身不处理 Promise,也不支持 async/await 写法;所有 Ajax 必须用 jQuery 的回调风格。
- 如果项目已升级 jQuery 3.0+,注意
.success()已废弃,一律用.done()+.fail() - 移动端需额外加防抖:连续快速点击提交,可能触发多个并发请求,后端需幂等设计或前端加锁变量
- 校验接口响应时间超过 1.5s,用户大概率会失去耐心,建议加 loading 动画或超时提示(
timeout: 3000) - 不要在
form.verify()里做任何异步操作,这个函数只适合放正则、长度、必填等同步检查
真正难的不是写 Ajax,而是把「异步结果」和「表单提交生命周期」对齐——Layui 没给你留钩子,只能自己接管 submit 事件,这点很容易被忽略。


















