element from表单源码分析,涉及到input、select、checkbox、picker、radio等组件的的验证。表单的验证用到了async-validator 插件。一起来看看吧。
首先form表单组件由两部分组成
- form: 统一管理form-item。
- form-item:负责完成验证等。
form
结构
1 | <form class="el-form" :class="[ |
结构很简单,form元素包裹插槽,也就是form-item
script部分
1.方便与form-item关联,注入form实例
1 | // 注入组件实例 |
2.实例创建后,fields收集form-item的实例
1 | created() { |
3.关于表单验证的一些方法,form组件是做是统一管理具体执行还是在form-item中
对整个表单进行验证
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46// 对整个表单进行验证
validate(callback) {
// 没有表单数据 抛警告跳出
if (!this.model) {
console.warn('[Element Warn][Form]model is required for validate to work!');
return;
}
let promise;
// 没有callback并且浏览器支持Promise return promise
if (typeof callback !== 'function' && window.Promise) {
promise = new window.Promise((resolve, reject) => {
callback = function(valid) {
valid ? resolve(valid) : reject(valid);
};
});
}
let valid = true;
let count = 0;
// 如果需要验证的fields为空,调用验证时立刻返回callback
if (this.fields.length === 0 && callback) {
callback(true);
}
let invalidFields = {};
// 遍历所有实例,一个个验证
this.fields.forEach(field => {
// 这里的validate是form-item的方法
field.validate('', (message, field) => {
// 如果有返回信息, 则说明验证失败
if (message) {
valid = false;
}
// 将错误对象复制到invalidFields
invalidFields = objectAssign({}, invalidFields, field);
// 调callback
if (typeof callback === 'function' && ++count === this.fields.length) {
callback(valid, invalidFields);
}
});
});
if (promise) {
return promise;
}
}objectAssign方法在utils/merge 中,合并对象的方法
对部分表单进行验证
1
2
3
4
5
6
7// 对部分表单验证
validateField(prop, cb) {
let field = this.fields.filter(field => field.prop === prop)[0];
if (!field) { throw new Error('must call validateField with valid prop string!'); }
// 验证对应表单规则的表单
field.validate('', cb);
}移除表单项的校验结果
传入待移除的表单项的 prop 属性组成的数组,如不传则移除整个表单的校验结果
1
2
3
4
5
6
7
8
9clearValidate(props = []) {
const fields = props.length
? this.fields.filter(field => props.indexOf(field.prop) > -1)
: this.fields;
fields.forEach(field => {
// form-item实例的方法clearValidate(清除验证状态与提示)
field.clearValidate();
});
}对整个表单进行重置,将所有字段值重置为初始值并移除校验结果
1
2
3
4
5
6
7
8
9
10
11
12resetFields() {
// 没有表单数据 return
if (!this.model) {
// 环境变量,非生产环境抛警告再return
process.env.NODE_ENV !== 'production' &&
console.warn('[Element Warn][Form]model is required for resetFields to work.');
return;
}
this.fields.forEach(field => {
field.resetField();
});
}
4.监听验证规则
1 | // 监听表单验证规则 |
form-item
结构
1 | <div class="el-form-item" :class="[{ |
外层div控制整体样式,内部分为两部分
- 第一部分:可展示label或拼接统一的后缀(from的属性)
- 第二部分:slot接收input,select等组件,以及验证不通过时的message展示
这里的变量elForm就是form组件provide的from实例
script部分
1.inject接收form实例,并向子孙后代注入form-item实例
1 | provide() { // 注入form-item实例 |
2.组件$el挂载到实例后
初始化,需要验证的让form组件收集起来,有验证规则的el.form.blur ,el.form.change 事件监听起来,等待触发验证。
1 | mounted() { |
- 这里用到的dispatch方法从mixins中引入:找到指定组件,发布指定事件。
3.验证方法
1 | validate(trigger, callback = noop) { |
4.清空验证状态与重置表单验证方法
1 | // 清空验证状态及message |
5.监听error以及验证状态
这里的error是props接收的:若传入,状态变为error,并显示错误信息
1 | watch: { |
6.实例销毁之前,发布form移除收集的该form-item实例
1 | beforeDestroy() { |
form表单组件与input等组件的关联
是怎么触发from验证的呢
form在mounted时监听了el.form.blur和el.form.change事件,并指定了验证的回调函数
1 | this.$on('el.form.blur', this.onFieldBlur); |
以input为例
1 | // form表单发布el.form.blur事件 |
以checkbox多选为例
1 | // 监听value 向上寻找form组件发布el.form.change事件暴露value(数组) |
等… , 这些时机触发校验
$on
就是监听指定的事件并且指定回调函数,$emit
就是发布某个事件并传递某些数据(可不传),当监听的事件名与发布的事件名一致就会触发监听的回调函数并且参数就是对应$emit
传递的参数。