rules.value = { ...rules.value, ...abc };
这行代码虽然是“设置校验规则”,但 因为 rules 是响应式对象,所以这个赋值会触发与其绑定的 el-form 的字段重新校验(自动触发了 validate),这不是你想要的行为。
我们目标是 修改 rules,但不要自动触发校验逻辑,而是等你手动 clearValidate() 或手动 validate()。
nextTick 可以让 clearValidate() 等待 DOM 和响应式更新完成之后再执行,避免在响应式更新过程中触发校验。
但是存在问题,如下:
🔍 为什么 nextTick() 不行? 在 Vue 3 和 Element Plus 的配合中:
rules.value = {...} 被设置后,Element Plus 的 内部会立即响应式触发 validate()。
nextTick() 等待的是 DOM 更新完成后执行队列,但 Element Plus 的 validate() 是 在响应式更新流程中直接触发的,早于 nextTick()。
rules.value = { ...rules.value, ...abc };
await nextTick(); // 太晚了,validate 已经触发
queryFormRef.value?.clearValidate(); // 来不及阻止
✅ 为什么 setTimeout(..., 0) 可以?
rules.value = { ...rules.value, ...abc };
setTimeout(() => {
queryFormRef.value?.clearValidate();
}, 0);
这是因为 setTimeout(..., 0) 会将 clearValidate() 放入浏览器的 事件循环任务队列的下一轮中,此时 DOM 和响应式都已经完成了:
✅ Vue 响应式更新完成 ✅ Element Plus 的 validate() 执行完 ✅ 此时你再 clearValidate() 就能把它擦掉,不会看到“自动触发校验”
Demo 如下:
// 基础rules
const rulesInit = {
noticeType: [
{ required: true, message: "调度通知类型不能为空", trigger: "blur" },
],
noticeTime: [
{ required: true, message: "调度通知时间不能为空", trigger: "blur" },
],
serialNumber: [
{ required: true, validator: validateSerialNumber, trigger: "blur" },
],
};
// 监听动态变化因素
watch(
() => noticeSubTypeList.value,
(newVal, oldVal) => {
if (newVal.length > 0) {
const abc = {
noticeSubType: [
{ required: true, message: "子类型不能为空", trigger: "blur" },
],
};
rules.value = { ...rules.value, ...abc };
setTimeout(() => {
queryFormRef.value?.clearValidate();
}, 0);
} else {
rules.value = { ...rulesInit };
setTimeout(() => {
queryFormRef.value?.clearValidate();
}, 0);
}
},
{ deep: true }
);