表单组件的核心需求
收集、校验、提交数据
分层设计
el-form,el-form-item,el-input等
职责分析
1.el-input:数据绑定到model的属性,触发校验
通过v-model双向绑定数据;通过dispatch
让el-form-item来$emit事件,达到触发校验的目的。
<template>
<div ...>
<input ... @blur="hanldeBlur">
</div>
</template>
<script>
export default {
methods: {
...,
handleBlur() {
this.dispatch('ElFormItem', 'el.form.blur', [this.value]);
},
...
}
}
</script>
this.dispatch
来自于mixins中的emitter,作用是不断查找和判断父组件是否是ElFormItem,找到之后就在这个父组件上$emit("el.form.blur", ...)
,然后ElFormItem通过监听el.form.blur
事件来校验。
2.el-form-item:根据校验规则做验证,控制显示错误信息
通过mounted
内监听事件(el.form.blur
)进行真正的校验;同时也通过dispatch
把自己保存在el-form里面,方便el-form对整个表单validate。
<template>
<div>
<label ...></label>
<div>
<slot></slot>
</div>
<div>
<template>
<script>
export default {
methods: {
validate(trigger, callback = noop) {
// 使用第三方库async-validator做规则校验
// 根据model,rules和prop获取el-input的值和校验规则rule
},
onFieldBlur() {
this.validate('blur');
},
addValidateEvents() {
this.$on('el.form.blur', this.onFieldBlur);
}
},
mounted() {
this.dispatch('ElForm', 'el.form.addField', [this]);
this.addValidateEvents()
}
}
</script>
3.el-form:设置form的数据对象和校验规则,以及主动触发对
表单进行校验。
<script>
export default {
provide() {
return {
elFormItem: this
};
},
props: {
model: Object,
rules: Object,
...
},
method: {
validate(callback) {
this.fields.forEach(field => {
field.validate('', (message, field) => {
...
});
});
}
},
created() {
this.$on('el.form.addField', (field) => {
if (field) {
this.fields.push(field);
}
});
}
}
</script>
意外发现
API文档中el-form-item也是可以接受rules,但是当同时指定el-form的rules和el-form-item的rules时,会优先使用el-form-item的rules。
getRules() {
let formRules = this.form.rules;
const selfRules = this.rules;
...
return [].concat(selfRules || formRules || []).concat(requiredRule);
}
组件库常用的技巧
1.mixins
通过 emitter
这个 mixins
,实现类似冒泡和广播
2.provide/inject
实现跨多层级的属性传递
3.发布-订阅模式
使用 emitter
中的 dispatch
。
4.slot插槽
组件设计肯定离不开插槽,el-form同时也使用了作用域插槽实现自定义error的显示
总结
el-form是一个很好的组件源码分析开始,代码设计思路清晰,用到都是基本api和知识点。
组件设计原则参考:https://engineering.carsguide...
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。