前言
在刚入行时候,只会知道如何使用表单组件,在后面一两年工作中也没有什么技术积累成为一个工具人,操作最多的就是ctrl+c和ctrl+v,在去年进了一家新公司,这家公司以前旧项目代码经过太多人的手,代码已经快不成人样了,难以维护,技术人员已经跑的差不多了,我进去好在让我们负责新的项目开发,要不然可能第二天就看不到我了,哈哈。项目主要面向于小程序和H5端,网上的UI库很难满足产品后续规划需求开发,只好开始研究组件原理及封装组件。
最近又个项目让我有开始接触element-ui,想到当初对el-form表单有一些困惑,查看一下源码和一些技术文章,对el-form有一些新的认识。
Form 表单
下面是一份el-form示例代码
-
-
"ruleForm" :rules="rules" ref="ruleForm"> -
"名字" prop="pass"> -
"password" v-model="ruleForm.pass"> -
-
"年龄" prop="age"> -
"ruleForm.age" > -
-
-
"primary" @click="submitForm('ruleForm')">提交 -
"resetForm('ruleForm')" >重置 -
-
-
-
-
首先要清楚一下组件的使用方式
el-form接收model和rule两个prop
- model表示表单绑定的数据对象
- rule表示验证规则策略,表单验证
el-form-item接收的prop属性,对应form组件的model数据中某个key值,如果rule刚好有key,给定的条件下去如失去焦点验证规则匹不匹配。
最终得到类似这样代码结构
-
-
-
-
- 姓名"form.name" />
-
-
- 年龄"form.age" />
-
-
- >提交
-
-
-
-
手写表单组件
组件中嵌套组件,主要是通过slot插槽,可以将组件拼接成上面代码结构。代码如下
el-form
-
-
-
-
-
-
el-form-item
-
-
-
-
-
-
el-input
-
- "text">
-
-
接下来就要考虑到组件中的通讯。由于组件中有可能嵌套很多的组件,如果单纯通过$parent和$children查找出来的父级组件,不一定是el-form组件。
两个问题:
- el-form-item组件如何得到el-form的数据
- el-form组件如何和el-form-item进行交互
解决第一问题,可以通过provide与inject实现。解决第二问题,就要讲到dispatch派发和broadcast广播
provide与inject
通过provide将当前表单实例传递到所有后代组件中,后代通过inject接受传递的值。
el-form
-
-
-
-
el-form-item
-
-
-
-
provide中this指el-form组件,this.elForm就能得到el-form组件中的数据和方法。
dispatch和broadcast广播
$dispatch与$broadcast是一种有历史的组件通信方式,因为他们是Vue1.0提供的一种方式,在Vue2.0中废弃了。
$dispatch: $dispatch会向上触发一个事件,同时传递要触发的祖先组件的名称与参数,当事件向上传递到对应的组件上时会触发组件上的事件侦听器,同时传播会停止。
$broadcast: $broadcast会向所有的后代组件传播一个事件,同时传递要触发的后代组件的名称与参数,当事件传递到对应的后代组件时,会触发组件上的事件侦听器,同时传播会停止(因为向下传递是树形的,所以只会停止其中一个叶子分支的传递)
$dispatch
-
- dispatch(componentName, eventName, params) {
- let parent = this.$parent || this.$root;//$parent 找到最近的父节点 $root 根节点
- let name = parent.$options.name; // 获取当前组件实例的name
- // 如果当前有节点 && 当前没名称 且 当前名称等于需要传进来的名称的时候就去查找当前的节点
- // 循环出当前名称的一样的组件实例
- while (parent && (!name||name!==componentName)) {
- parent = parent.$parent;
- if (parent) {
- name = parent.$options.name;
- }
- }
- // 有节点表示当前找到了name一样的实例
- if (parent) {
- parent.$emit.apply(parent,[eventName].concat(params))
- }
- },
$broadcast
-
- broadcast(componentName, eventName, params) {
- // 循环子节点找到名称一样的子节点 否则 递归 当前子节点
- this.$children.map(child=>{
- if (componentName===child.$options.name) {
- child.$emit.apply(child,[eventName].concat(params))
- }else {
- broadcast.apply(child,[componentName,eventName].concat(params))
- }
- })
验证表单
async-validator是一个表单的异步验证的第三方库,也是element-ui 中的form组件所使用的验证方式。
el-form-item
-
-
- >{{label}}
-
- {{errorMessage}}
-
-
-