element表单自动触发校验?

1,628 阅读2分钟

问题:当弹出新增/编辑弹窗的时候,没有点确定按钮也进行了必填校验

一般我们遇到这种问题都是直接使用clearValidate进行清除校验,我在打开弹窗和关闭弹窗的时候都对其进行了清除校验,还是会触发。然后我发现当注释掉form表单赋空值相关语句就不会触发了。

下面我们从框架源码角度分析一下是怎么触发的。

  form.vue
// 表单校验 参数是一个回调函数 (valid, invalidFields)
    validate(callback) {
      if (!this.model) {
        console.warn('[Element Warn][Form]model is required for validate to work!');
        return;
      }
      let promise;
      // 如果没有回调函数,则返回promise
      if (typeof callback !== 'function' && window.Promise) {
        promise = new window.Promise((resolve, reject) => {
          callback = function (valid, invalidFields) {
            valid ? resolve(valid) : reject(invalidFields);
          };
        });
      }

      let valid = true;
      let count = 0;
      // 如果需要验证的fields为空,调用验证时立刻返回callback
      if (this.fields.length === 0 && callback) {
        callback(true);
      }
      let invalidFields = {};
      // 表单项循环校验
      this.fields.forEach((field) => {
        field.validate('', (message, field) => {
          if (message) {
            valid = false;
          }
          invalidFields = objectAssign({}, invalidFields, field);
          if (typeof callback === 'function' && ++count === this.fields.length) {
            callback(valid, invalidFields);
          }
        });
      });

      if (promise) {
        return promise;
      }
    },

上面的代码是form表单的校验方法,通过看源码发现,表单校验实际是循环校验每一个表单项。接下来我们查看form-item组件的校验触发时机。

 // 输入框失焦 触发校验
    onFieldBlur() {
      this.validate('blur');
    },
    // 输入框改变(model对象的属性值发生变化也会触发) 触发校验
    onFieldChange() {
      console.log('触发了onFieldChange');
      if (this.validateDisabled) {
        this.validateDisabled = false;
        return;
      }

      this.validate('change');
    },

通过查看代码发现,在onFieldBlur函数和onFieldChange函数中有调用validate校验方法。

// 添加校验事件
    addValidateEvents() {
      // 获取校验规则
      const rules = this.getRules();

      if (rules.length || this.required !== undefined) {
        // 监听form的blur 和 change事件
        this.$on('el.form.blur', this.onFieldBlur);
        this.$on('el.form.change', this.onFieldChange);
      }
    },

而这两个方法是作为el.form.blur和el.form.change监听的回调函数。 那么只要我们找到在哪里触发这两个监听函数不就找到了吗? form-item组件下面都是一些input、select、checkbox等表单元素,要对form-item进行校验就需要获取input等表单元素的值,以这个为切入点,我们以input为例,看看input源码。

watch: {
   value(val) {
      this.$nextTick(this.resizeTextarea);
      if (this.validateEvent) {
        this.dispatch('ElFormItem', 'el.form.change', [val]);
      }
    },
}

在input组件源码我们发现,该组件对input的值(value)进行了监听,变化触发el.form.change监听,然后执行onFieldChange回调,进行校验,这里的dispatch是用于找到目标父节点(ElFormItem),并触发(el.form.change)监听,带上val参数。

总结

因为我定义的表单属性初始值是空字符串,而后台返回的数据为null, 赋值的时候触发了change监听,进而进行了校验。我们需要保证赋空值的时候需要和初始值保持一致,或者判断一下后台返回的是空值的时候,不进行赋值。