清除动态添加_rules_的校验导致的副作用

4 阅读1分钟
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 }
);