实现Vue表单验证插件

栏目: 编程语言 · 发布时间: 5年前

内容简介:表单验证存在于每一个后台系统中,它承载了许多的逻辑以及状态。但是,过于某些的场景,会导致代码臃肿,如何更好地梳理它,来解决开发的痛点。上篇文章介绍了,如何函数式调用表单组件从而减少维护其状态的方法实例:

表单验证存在于每一个后台系统中,它承载了许多的逻辑以及状态。但是,过于某些的场景,会导致代码臃肿,如何更好地梳理它,来解决开发的痛点。

1. 前言

上篇文章介绍了,如何函数式调用表单组件从而减少维护其状态的方法 基于Vue构造器创建Form组件的通用解决方案 。现在来介绍下如何处理表单验证问题,现有的Vue表单验证插件有 vuelidatevee-validate 等,但是如果场景简单的话,没有引入插件的必要,但是场景复杂的话,验证规则又要定制化的时候,应用起来没那么顺手。所以,如何调教出一个听话的Vue表单验证插件,是十分有必要的。

2. 实例以及使用规则

实例: fatge.xyz/blog/juejin…

实例代码: GitHub - FatGe/fat-validator: fat-validator-demo

源码: GitHub - FatGe/fat-validator: fat-validator

代码中,有

<template>
<input 
    placeholder="请输入"
    :class="['native-input', { 'error': !errors.get('nativeInput').success }]"
    v-model="form.nativeInput"
    v-validate:nativeInput.blur="validates.nativeInput"
    @focus="errors.reset('nativeInput')"
/>
<span class="u-info">{{ errors.get('nativeInput').warn }}</span>
</template>
<script>
// mixin 验证结果validateResult
import { validateResult } from 'fat-validator'

export default {
    mixins: [ validateResult],
    data () {
        return {
            form: {
                nativeInput: ''
            },
            validates: {
                nativeInput: [
                    {
                        // 将this指针bind在当前组件内,省去传值
             	        need: () => !!this.form.nativeInput,
                        warn: '不能为空'
                    }
                ]
            }
        }
    }
}
</script>
复制代码

上述代码中存在一下几点:

  • 组件的 data 中维护表单的数据 form 以及待验证的规则 validates ,通过 () => {} ,将 this 指针绑定在当前组件内,省去传值;

  • v-validate:nativeInput.blur 当前 input 需要校验,校验结果的key为 nativeInputblur 代表失焦校验;

  • 校验规则以及警告信息则维护在组件的 datavalidates 中;

  • 校验结果为 errors.get('nativeInput') ,其包含 { success: true, warn }

3. 原理

从实例中的 v-validate:nativeInput.blur 可以看出,选用了自定义指令作为连接被校验组件和校验规则之间的桥梁,主要是它两个特点:

  • 钩子函数:Vue自定义指令,存在着 bindinsertedupdate 等钩子函数,其中 bindunbind 与元素的display息息相关,这样满足了表单挂载、注销的语义,且只触发一次;
  • 构造函数提供了大量的参数,可以方便与组件通信,如 elbind 等; 该自定义指令的注册如下。
Vue.directive('validate', {
    bind (element, binding, vnode) {
        // 传给参数arg => 作为校验结果中的key
        // 指令绑定值value => 作为校验规则
        // 修饰符modifiers => 作为出发校验的event类型
        const {
            arg: name,
            modifiers,
            value: rules
        } = binding
        const method = Object.keys(modifiers)[0]
    },
    unbind (element, binding) {
        // 注册
        const { arg: name, modifiers } = binding
        const method = Object.keys(modifiers)[0]
    }
})
复制代码

上述code解释了:

  • 通过 this 指针将Form组件中 data 传递给验证规则 need function
  • 以及如何将rules传入指令中。

接下来介绍如何处理这些规则。为了减少代码之间的耦合,构建一个中间件作为了规则处理的处理中心,整体结构就变为下图

实现Vue表单验证插件

从组件到规则处理中心之间的通信如下

export default function (Vue) {
    Vue.directive('validate', {
        bind (element, binding, vnode) {
            //... pre code
            // 获取当前组件的context
            context = vnode.context
            // 将eventHandler$$1绑定在当前Form的context
            // 防止动态切换时无法与组件通信
            if (eventHandler$$1) {
                eventHandler$$1.bind(context)
            } else {
                eventHandler$$1 = new eventHandler(context)
            }
            // 如果method存在的话,当event出发时的处理函数
            const handler = function () {
                eventHandler$$1.broadcast(name)
            }
            // 在hanler中订阅一个规则处理对象
            eventHandler$$1.subscribe({
                name,
                method,
                rules,
                element,
                handler
            })

            method && on(element, method, handler)
        },

        unbind (element, binding) {
            //... pre code
			  
            // 当Form注销时,垃圾处理
            const handler = eventHandler$$1.removeSubscribe(name)
				
            method && off(element, method, handler)
        }
    })
}
复制代码

当完成组件上 v-validate 的解析时,就会在处理中心中订阅一个校验对象。处理中心的定义如下

export default class eventHandler {
    // 构造函数
    constructor (context) {
        this.context = context
        this.subscribers = {}
    }
    // 动态切换
    bind (context) {
        this.context = context
    }
    // 订阅,将其维护在eventHandler的subscribers内
    subscribe (options) {
        const { name } = options
        this.subscribers[name] = Object.assign({}, options)
    }
    // 当校验事件触发时,进行校验
    broadcast (name) {
        const { context, subscribers } = this
        const { rules } = subscribers[name]
        // 校验结果
        const error = findFailRule(rules)
        
        return error.success
    }
}
复制代码

需要校验时就会触发,一般的触发条件可以归类为以下两类:

  • input event:blur、change、input等;
  • 当点击Form的确认button时,或组件的指定event触发时。 会broadcast,通过findFailRule来获得验证失败的结果。
findFailRule = (value = {}, rules) => {
    let failRule = null
    if (Array.isArray(rules)) {
        failRule = rules.find(item => {
            return !item.need(value)
        })
    }
    return {
        warn: failRule ? failRule.warn : '',
        success: !failRule
    }
}
复制代码

在组件的data中,

validates: {
    nativeInput: [
        {
            need: () => !!this.form.nativeInput,
            warn: '不能为空'
        }
    ]
}
复制代码

将验证规则定义为Array,这样方便遍历,同时也会只获取第一个报错信息。 在broadcast中获取了验证结果之后,就需要将其传递给组件。

const validateResult = {
    data () {
        return {
            errors: {
                get (param) {
                    return this[param]
                        ? this[param]
                        : {
                            warn: '',
                            success: true
                        }
                }
            }
        }
    }   
}
复制代码

维护一个 validateResult 对象,通过 mixins 注入到Form组件内,在之前,我们将 eventHandler 绑定在当前 context 内,这样可以获取到注入的 errors 状态,当校验完成时

broadcast (name) {
    const { context, subscribers } = this
    const { element, rules } = subscribers[name]
    const error = findFailRule(rules)
    // 脏更新
    context.errors[name] = error
    context.$forceUpdate()
    return error.success
}
复制代码

以上是一个简单的Vue表单验证插件的雏形,为了方便开发业务,还需它具备以下API:

validate
validateAll
reset
resetAll

为了方便引入,利用 Vue.use() 将上述自定义指令封装程Vue的插件。


以上所述就是小编给大家介绍的《实现Vue表单验证插件》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

共享经济

共享经济

[美] 罗宾•蔡斯 / 王芮 / 浙江人民出版社 / 2015-9-25 / 59.90元

[内容简介]  在当今这个稀缺的世界里,人人共享组织可以创造出富足。通过利用已有的资源,如有形资产、技术、网络、设备、数据、经验和流程等,这些组织可以以指数级成长。人人共享重新定义了我们对于资产的理解:它是专属于个人的还是大众的;是私有的还是公有的;是商业的还是个人的,并且也让我们对监管、保险以及管理有了重新的思索。  在这本书中,罗宾与大家分享了以下观点:  如何利用过剩......一起来看看 《共享经济》 这本书的介绍吧!

RGB转16进制工具
RGB转16进制工具

RGB HEX 互转工具

RGB CMYK 转换工具
RGB CMYK 转换工具

RGB CMYK 互转工具

HSV CMYK 转换工具
HSV CMYK 转换工具

HSV CMYK互换工具