Vue 2 无视组件边界的表单校验解决方案

Vue 2 无视组件边界的表单校验解决方案

💡 原文中文,约5800字,阅读约需14分钟。
📝

内容提要

文章介绍如何用约百行代码自建 Vue 2 表单校验插件:通过自定义指令 v-vld 配合 mixin 注入 errList,利用 bind、unbind、componentUpdated 钩子注册和更新校验,支持组件与原生 DOM 两种绑定,失焦时校验并响应式显示错误;并提供 $vld 方法实现提交前批量校验,可按 name 定位并滚动到出错输入框。

🔎

延伸解读

自定义指令与 mixin 的协作机制

文章通过自定义指令 v-vld 和全局 mixin 注入 errList 实现校验。指令的 bind 钩子负责注册输入框信息,unbind 清理,componentUpdated 更新校验规则。mixin 为每个组件实例混入 errList 数据,用于存储错误信息。这种设计将校验逻辑与组件解耦,但 mixin 会混入所有实例,需注意精简以避免性能开销。

组件与原生 DOM 绑定的差异处理

v-vld 可绑定到 Vue 组件或原生 DOM 元素。绑定组件时,通过 vnode.componentInstance 获取实例,利用 $watch 监听 value 变化;绑定原生元素时,则通过 addEventListener 监听 change 事件。两者在获取 name、scope 和 id 的方式上不同:组件使用 uid 作为唯一标识,原生元素则依赖 name 属性,若 name 重复可能导致错误。

提交前批量校验与错误定位

通过 Vue.prototype.$vld 方法实现提交前批量校验,可传入 scope 筛选特定范围的输入框。校验失败时,错误信息以 {field, msg} 格式返回,field 对应输入框的 name。利用该字段,可通过 document.querySelector 滚动到出错位置。这为表单提交提供了便捷的校验和定位机制,但需确保 name 唯一性。

轻量自建插件的适用性与局限

文章强调该插件约百行代码,适合自用,但过度定制化,未考虑所有配置。相比 vee-validate 等库,它更轻量且避免子组件校验引发的父组件渲染卡顿。然而,它缺乏复杂场景支持,如嵌套表单、数组结构或自定义模板的修改日志记录。读者应根据项目需求调整,不宜直接用于生产环境。

❓

Q&A

Vue 2 中如何自己实现一个轻量的表单校验插件?

通过自定义指令 v-vld 和 mixin 注入 errList 来实现。指令的 bind 钩子中注册校验,利用 vnode.componentInstance 或 vnode.elm 区分组件与原生 DOM,监听值变化进行校验,错误信息存入 errList 响应式显示。

v-vld 指令如何同时支持 Vue 组件和原生 DOM 元素?

在 bind 钩子中通过 vnode.componentInstance 判断是否绑定在 Vue 组件上。如果是组件,则使用 vm.$props 或 vm.$attrs 获取 name 和 scope,并监听 vm.value 的变化;如果是原生 DOM,则使用 elm.getAttribute 获取属性,并添加 change 事件监听。

v-vld 指令的 bind、unbind 和 componentUpdated 钩子分别有什么作用?

bind 用于初始化注册校验,将输入框信息存入 vldList 并设置监听;unbind 用于清理,删除 errList 中的错误记录和 vldList 中的注册信息;componentUpdated 用于在指令值变化时更新校验规则,并清除旧错误。

如何使用 $vld 方法进行提交前批量校验?

通过 Vue.prototype.$vld 方法,传入 scope 参数可批量校验指定范围的输入框。方法遍历 vldList,根据当前值执行校验,更新 errList,并返回错误数组,格式为 [{ field: String, msg: String }]。

校验失败后如何自动滚动到出错的输入框?

利用校验返回的 field 字段(即输入框的 name),通过 document.querySelector(`[name*="${name}"]`).scrollIntoView() 实现自动滚动定位。

为什么作者建议不要直接使用这个插件,而是自行修改?

因为插件是“过度定制化”的,很多配置没有考虑周全,直接使用可能不适用于所有场景。作者建议根据自身项目需求修改到最合手的状态,以保持精简和扩展性。

🏷️

标签

➡️

继续阅读