使用组件就像流水线上的工人;设计组件就像设计流水线的人,设计好了给工人使用。
一. 目标
仿 ElementUI 实现一个简单的 Form 表单,主要实现以下四点:
Form
FormItem
Input
表单验证
我们先看一下 ElementUI 中 Form 表单的基本用法
登录
在 ElementUI 的表单中,主要进行了 3 层嵌套关系, Form 是最外面一层, FormItem 是中间一层,最内层是 Input 或者 Button 。
二. 创建项目
我们通过 Vue CLI 3.x 创建项目。
使用 vue create e-form 创建一个目录。
使用 npm run serve 启动项目。
三. Form 组件设计
ElementUI 中的表单叫做 el-form ,我们设计的表单就叫 e-form 。
为了实现 e-form 表单,我们参考 ElementUI 的表单用法,总结出以下我们需要设计的功能。
e-form 负责全局校验,并提供插槽;
e-form-item 负责单一项校验及显示错误信息,并提供插槽;
e-input 负责数据双向绑定;
1. Input 的设计
我们首先观察一下 ElementUI 中的 Input 组件:
在上面的代码中,我们发现 input 标签可以实现一个双向数据绑定,而实现双向数据绑定需要我们在 input 标签上做两件事。
要绑定 value
要响应 input 事件
当我们完成这两件事以后,我们就可以完成一个 v-model 的语法糖了。
我们创建一个 Input.vue 文件:
export default {
name: "EInput",
props: {
value: { // 解释一
type: String,
default: '',
}
},
data() {
return {
valueInInput: this.value // 解释二
};
},
methods: {
handleInput(event) {
this.valueInInput = event.target.value; // 解释三
this.$emit('input', this.valueInInput); // 解释四
}
},
};
我们对上面的代码做一点解释:
**解释一:**既然我们想做一个 Input 组件,那么接收的值必然是父组件传进来的,并且当父组件没有传进来值的时候,我们可以它一个默认值 "" 。
**解释二:**我们在设计组件的时候,要遵循单向数据流的原则:父组件传进来的值,我们只能用,不能改。那么将父组件传进来的值进行一个赋值操作,赋值给 Input 组件内部的 valueInInput ,如果这个值发生变动,我们就修改内部的值 valueInInput 。这样我们既可以处理数据的变动,又不会直接修改父组件传进来的值。
**解释三:**当 Input 中的值发生变动时,触发 @input 事件,此时我们通过 event.target.value 获取到变化后的值,将它重新赋值给内部的 valueInInput 。
**解释四:**完成了内部赋值之后,我们需要做的就是将变化后的值通知父组件,这里我们用 this.$emit 向上派发事件。其中第一个参数为事件名,第二个参数为变化的值。
完成了以上四步,一个实现了双向数据绑定的简单的 Input 组件就设计完成了。此时我们可以在 App.vue 中引入 Input 组件观察一下结果。
import EInput from './components/Input.vue';
export default {
name: "app",
components: {
EInput
},
data() {
return {
initValue: '223',
};
},
};
2. FormItem 的设计
在 ElementUI 的 formItem 中,我们可以看到:
需要 label 来显示名称;
需要 prop 来校验当前项;
需要给 input 或 butto