缘起

以前做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

参考文章

Vue.js 组件精讲

Logo

前往低代码交流专区

更多推荐