如何封装一个带表单验证的 Vue的表单插件(一):起步
缘起以前做Vue项目,经常需要用到表单验证,当时为了项目的速度,为了更好的交互和上线之后更稳定的性能,一直使用的都是VeeValidate确实很好用很强大,但是复杂的英文API的确也在开发中给我带了一定的困难,再加上项目上的需求或多或少和插件有一点点的差别,去看源码修改插件这种事情对我这个菜鸟压力太大~~;一直痛并快乐着。——————————————————————————————————...
缘起
以前做Vue项目,经常需要用到表单验证,当时为了项目的速度,为了更好的交互和上线之后更稳定的性能,一直使用的都是
VeeValidate
确实很好用很强大,但是复杂的英文API的确也在开发中给我带了一定的困难,再加上项目上的需求或多或少和插件有一点点的差别,去看源码修改插件这种事情对我这个菜鸟压力太大~~;一直痛并快乐着。
在闲鱼时间,一直希望可以系统学习一下如何封装一个form表单插件,一方面解决工作上面的痛点,一方面可以牢固所学知识。
??????????????????????????????????????????????????????????
效果
下面的动图就是我最近学习写出来的效果,功能简单,但也因此,容易应对不通项目需求更快速的做出适当定制~
分析与准备
form表单组件属于基础组件(不包含任何业务逻辑 只包含某种独立功能的组件,比如模态框、日历插件也是基础组件,这种组件适用于大多数项目,通过高度抽象的API 和可定制化选项匹配大多数项目)
所以说,我们不能在form表单组件里面出现业务逻辑,它要适用于绝大多数的需要表单校验的地方,在这个表单组件里,我们使用 异步表单验证插件 async-validator。很多大型的UI框架都是使用这个插件,使用比较简单,大家可以直接去GitHub上面查看使用文档。
拆分
封装一个基础组件,一定要记住一个词 单一职责,就是一个组件模块做一件事,如果功能不同职责不一一定要再次拆开,这样可以减少代码耦合,增加组件的可复用性,逻辑更加清晰。
下面我们进入正题,我们将组件整个form表单组件分为三个部分:
- 表单元素组件,也就是input、textarea、select这些原生HTML标签,组件的主要功能是接受父级传入的值并将自身改变的值传到父组件(也就是双向数据绑定),另外将触发校验的事件传给外面的监听器,将value作为回调函数的参数。
- form-item组件,独立的表单校验组件,此组件监听表单元素组件的触发校验的事件,获取当前用户设置的校验规则以校验的值(只是当前form-item)。设置表单校验的状态和报错信息。简而言之,表单的验证工作就是又form-tem组件完成。
- form组件,作为全部校验的功能组件,form表单通常会有一个提交按钮,可以出发整个表单的校验工作。
简单分析完了我们即将详细讲解的几个组件,接下来我们提前分析几个特殊的功能函数,在一般写Vue 项目中我们很少用上的,但是在基础组件中,非常实用的几个工具函数。
工具函数(方法)
1、 首先我们说的第一个方法是 dispatch,作用是向上指定组件暴露事件 以供监听,不限层级,直到找到为止,代码如下:
export default {
methods: {
dispatch (componentName, eventName, params) {
let parent = this.$parent || this.$root
let name = parent.$options.name
while (parent && (name !== componentName)) {
parent = parent.$parent
if (parent) {
name = parent.$options.name
}
}
parent.$emit(eventName, params)
}
}
方法接受三个参数:
- componentName 指定的向上组件name值(提倡每个.vue文件都要有自己的专属name)
- eventName 上级监听的事件名
- params 事件回调的值
2、 第二个方法是 capture,作用是向下指定组件暴露事件 以供监听,不限层级,直到找到为止,代码如下:
function loops (childrens, componentName, eventName, params) {
for (let child of childrens) {
let name = child.$options.name
if (name && name !== componentName) {
loops(child.$children, componentName, eventName, params)
} else {
child.$emit(eventName, params)
}
}
export default {
methods: {
capture (componentName, eventName, params) {
let childrens = this.$children
loops(childrens, componentName, eventName, params)
}
}
方法接受三个参数:
- componentName 指定的向下的组件name值(提倡每个.vue文件都要有自己的专属name)
- eventName 子级监听的事件名
- params 事件回调的值
之所以用到这两个方法,是因为我们的form的三个基础组件之间并不一定是紧密相连的父子组件关系,用户还可能在其中嵌套其他组件,在这种情况下我们不能限制用户的组件嵌套方式。
3、另外我们还要用到
- 向上查找最近的最近的指定组件 findComponentUpward
- 向下查找所有指定的组件 findComponentsDownward
// 向上寻找指定name的组件
function findComponentUpward (context, componentName) {
let parent = context.$parent
if (!parent) {
return
}
let name = parent.$options.name
if (name === componentName) {
return parent
} else {
return findComponentUpward(parent, componentName)
}
}
export { findComponentUpward }
// 向下寻找指定name的所有组件
function findComponentsDownward (context, componentName) {
return context.$children.reduce((components, child) => {
if (child.$options.name === componentName) components.push(child)
const foundChilds = findComponentsDownward(child, componentName)
return components.concat(foundChilds)
}, [])
}
export { findComponentsDownward }
现在我们前期的准备工作基本完成了,接下来我们要开始真正的form表单组件编写了~~
备注
源码地址: https://github.com/wangyangsea/wy-validate
参考文章
更多推荐
所有评论(0)