场景:
自定义组件在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-input blur会触发检验,首先从触发源开始,即el-input。
在源码中可以看到这一段处理:
handleBlur(event) {
this.$emit('blur', event);
if (this.validateEvent) {
this.dispatch('ElFormItem', 'el.form.blur', [this.currentValue]);
}
}
从上面逻辑中可以得到如下信息:
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组件中对应的处理逻辑,在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(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下。