表单异步校验时怎么处理 loading 状态和错误提示?
我在用 Vue 写一个注册表单,用户名需要异步校验是否重复。现在的问题是:校验过程中没法显示 loading,而且如果请求失败了,错误信息也覆盖不了之前的提示。
我试过在 asyncValidator 里手动控制 loading 变量,但好像时机不对,UI 没反应。比如这样:
const validateUsername = async (rule, value) => {
if (!value) return Promise.reject('请输入用户名');
loading.value = true;
try {
const res = await checkUsername(value);
loading.value = false;
return res.available ? Promise.resolve() : Promise.reject('用户名已存在');
} catch (err) {
loading.value = false;
return Promise.reject('校验失败,请重试');
}
};
但界面上的 loading 图标根本不显示,错误信息有时候也会残留。这到底该怎么搞?
具体来说,用 el-form 的
validate或validateField方法前手动设 loading,校验结束后再关掉,错误提示交给 form-item 的error属性或者表单实例的validate返回结果来处理。比如这样写:
然后在模板里:
关键点是:
- loading 要在调用校验前后手动控制,别塞进 asyncValidator 里,因为那个函数是同步返回 Promise 的,Vue 的响应式更新可能来不及
- 网络错误要在 checkUsername 里先 catch 一下,转成校验失败的 reject,这样外面统一处理就行
- 如果你用的是 el-form-item,它自带 error 显示逻辑,只要 reject 的字符串能传到它那儿,就不会残留——除非你多次快速触发校验导致旧的 reject 覆盖了新的,这种情况可以用
validateField的第二个参数传入 callback 来更精细控制,但一般场景不用这么复杂我之前也踩过这个坑,以为在 asyncValidator 里设 loading 能联动,结果发现 Vue 的响应式更新是在 asyncValidator 返回之后才触发的,UI 自然就卡住了。后来才明白:校验逻辑和 UI 状态控制得分开写,别混在一起。