Element中自定义组件校验的背后

前言

场景:

自定义组件在Element UI form组件中支持校验

处理方法:

  • 使用el-form中提及的validateField方法主动触发

  • 在对应的el-form-item调用$emit分发事件

this.$refs['formItem'].$emit('el.form.blur')

这是最近有个需求点引发了我对于Element UI框架中el-form校验相关的处理。

具体逻辑

分析基于的实例:





上面是最基本的form实例,当el-input blur会触发检验,仅此而已。

上面实例中需要研究三个组件(与校验相关的处理逻辑):

  • el-form
  • el-form-item
  • el-input

当el-input blur会触发检验,首先从触发源开始,即el-input。

el-input校验相关

在源码中可以看到这一段处理:


handleBlur(event) {
  this.$emit('blur', event);
  if (this.validateEvent) {
    this.dispatch('ElFormItem', 'el.form.blur', [this.currentValue]);
  }
}

从上面逻辑中可以得到如下信息:

  • blur触发会调用handleBlur处理程序
  • handleBlur处理程序中主要做了两件事:分发blur事件和el.form.blur事件
this.dispatch('ElFormItem', 'el.form.blur', [this.currentValue]);

而上面代码则是触发校验的源头,dispatch方法实现的功能可以肯定是分发了,而且可以猜测这里不使用$emit,那就是可能就是实现Vue.js 1.0中的类似dispatch的功能:

可向祖先组件传递相应的事件

通过源码获悉dispatch是位于src/mixins/emitter.js文件中的,接下来就看看这边的具体处理。

dispatch(componentName, eventName, params) {
    var parent = this.$parent || this.$root;
    var name = parent.$options.componentName;
    // 从这里可以看出是找到对应的组件对象
    while (parent && (!name || name !== componentName)) {
        parent = parent.$parent;
        if (parent) {
          name = parent.$options.componentName;
        }
    }
    if (parent) {
      parent.$emit.apply(parent, [eventName].concat(params));
    }
}
this.dispatch('ElFormItem', 'el.form.blur', [this.currentValue]);

这里dispatch方法实现的功能:

找到对应的父组件,调用$emit事件来实现事件分发

而实例这里的处理就是:

表示el-form-item的组件对象来调用$emit el.form.blur事件

这里就要看看el-form以及el-form-item对应的处理。

el-form-item校验相关

首先是el-form-item组件中对应的处理逻辑,在mounted生命周期函数中,找到了相关处理,如下:

mounted() {
    if (this.prop) {
        // 其他相关处理
        if (rules.length || this.required !== undefined) {
            this.$on('el.form.blur', this.onFieldBlur);
          	this.$on('el.form.change', this.onFieldChange);
        }
    }
},

在el-form-item组件创建过程中就对el.form.blur事件有监听处理了,el.form.blur会调用onFieldBlur函数,而这里就是el-form校验处理的核心了。

而onFieldBlur实际上是调用validate方法,如下:

onFieldBlur() {
    this.validate('blur');
},
validate

主要的处理逻辑如下:

validate(trigger, callback = noop) {
    // 获取相关规则
    const rules = this.getFilteredRule(trigger);
    if ((!rules || rules.length === 0) &&
        this.required === undefined) {
        callback();
        return true;
    }
    const descriptor = {};
    if (rules && rules.length > 0) {
       rules.forEach(rule => {
        delete rule.trigger;
       });
    }
    descriptor[this.prop] = rules;
    // 创建校验器对象,异步验证库async-validator
    const validator = new AsyncValidator(descriptor);
    const model = {};
    model[this.prop] = this.fieldValue;
    // validate方法具体的参数构建
    validator.validate(model,
      { firstFields: true },
     (errors, invalidFields) => {
        this.validateState = !errors ? 'success' : 'error';
        this.validateMessage = errors ? errors[0].message : '';
        callback(this.validateMessage, invalidFields);
        this.elForm && this.elForm.$emit('validate', this.prop, !errors);
     });
},

总结

从上面整个的逻辑可以知道Element UI组件中整个校验相关的处理逻辑,从上面的处理逻辑中可以对自定义组件如何实现校验的背后有了更好的理解。

Element UI Form组件的校验是使用了async-validator库,具体相关的使用以及细节感兴趣可以去view下。

你可能感兴趣的:(Vue相关)