摘要:今天就来介绍一下如何利用的自定义指令来开发一个表单验证插件的过程。按照这种方式就能够使用自己开发的这个表单校验插件。
这段时间在进行一个新项目的前期搭建,新项目框架采用vue-cli3和typescirpt搭建。因为项目比较轻量,所以基本没有使用额外的ui组件,有时候我们需要的一些基础组件我就直接自己开发了。今天就来介绍一下如何利用vue的自定义指令directive来开发一个表单验证插件的过程。
1.vue插件开发关于vue的插件开发,官方文档里有很清晰的说明,详情可以去阅读开发文档。我自己开发的表单验证插件validate.ts和loading,messageBox插件都是利用了这种方式。今天先来看表单验证插件的开发。
vue全局指令
// myPlugin.js
export default {
install: (Vue, options) => {
// 注册一个my-directive指令
Vue.directive("my-directive", {
bind(el, binding, vnode, oldVnode) {
// 逻辑
}
...
})
}
}
// main.js
import Vue from "vue";
import myPlugin from "myPlugin";
Vue.use(myPlugin);
上面是注册一个vue指令插件的写法。值得注意的是注册自定义指令的时候,bind()函数为指令的钩子函数,其中的参数el表示指令绑定的元素,可以直接操作DOM。binding表示一个对象,包括指令名称,绑定值等信息。vnode和oldVnode表示Vue编译生成的虚拟节点。
我们通过注册一个全局指令v-validateParams指令,绑定到输入表单的input标签上来校验当前输入值是否符合要求。
2.v-validateParams指令最开始我参考了网上的一些代码。基础的实现如下:
整体框架
import Vue from "vue"
export default {
install: (Vue, options) => {
// 注册一个全局自定义指令 `v-validateParams`
Vue.directive("validateParams", {
// 当被绑定的元素插入到 DOM 中时
inserted: function (el, binding, vNode) {
// 给指令绑定的Dom元素添加事件监听,监测输入框失焦事件
// 每次当表单中的输入框失焦时执行函数
el.addEventListener("blur", function (event) {
// 1.首先重置所有错误提示
// 2.获取自定义指令中传入的校验规则参数和表单输入的值
// 3.依次判断当前输入的值是否符合校验规则
})
}
})
// 注册一个全局自定义指令 `v-validateSubmit`,这个指令绑定到表单的提交button上
Vue.directive("validateSubmit", {
// 当被绑定的元素插入到 DOM 中时
inserted: function (el, binding, vNode) {
// 给提交button添加事件监听
el.addEventListener("click", function (event) {
// 获取当前组件内所有含有v-check类名的元素
let elements = vNode.context.$el.getElementsByClassName("v-check")
var evObj = vNode.context.$el.createEvent("Event")
evObj.initEvent("blur", true, true)
for (let element of elements) {
// 给所有v-check元素绑定blur事件
element.dispatchEvent(evObj);
}
// 获取当前组件下的所有错误提示元素
let errorInputs = vNode.context.$el.getElementsByClassName("input-error");
// 如果组件中没有错误提示元素,则执行当前组件实例中的submit()函数
if(errorInputs.length === 0){
vNode.context.submit();
}
})
}
})
}
}
这里需要着重说明一下validateSubmit指令,这个指令绑定到提交按钮上,在点击的时候执行校验,校验通过之后执行提交操作。但是这里的实现方式不是特别友好:
1.需要获取当前组件中的所有input元素,给他们绑定并执行blur事件,以此来执行validateParams指令中的校验逻辑。
2.需要获取当前组件中的所有错误提示元素,如果他们存在就不能执行提交操作。
3.当组件内不含任何错误提示元素时,就表示校验通过,执行当前组件内的submit函数,所以每个表单组件的提交函数都只能命名为submit
然后我们再看下指令validateParams,该指令需要绑定到表单input元素上,并把校验规则当作参数写入。当该input元素失焦时,会执行指令中给当前元素绑定的事件中的逻辑。这些逻辑分为三个步骤,我已经写在注释里了,现在我们来看下具体实现。
重置所有错误提示
/**
* 重置当前节点样式
* @param el: HTMLElement,传入当前绑定的input元素
*/
const resetError = (el: HTMLElement) => {
el.className = el.className.replace("input-error", "").trim();
if ( el.parentNode ) {
const ErrorNode = el.parentNode.querySelector(".error-tips");
if (ErrorNode) {
el.parentNode.removeChild(ErrorNode);
}
}
};
获取自定义指令中传入的校验规则参数和表单输入的值
// binding.value是传入自定义指令的参数,以数组的形式
for (const rule of binding.value) {
// 分别获取到自己定义的校验规则并执行
const { min, max, message, required, pattern } = rule;
if ( min && InputEl.value.length < min ) {
// 如果不符合校验,执行报错函数
validateError(InputEl, message);
break;
}
if ( max && InputEl.value.length > max ) {
validateError(InputEl, message);
break;
}
if ( !!required && !InputEl.value ) {
validateError(InputEl, message);
break;
}
if ( pattern && !pattern.test(InputEl.value) ) {
validateError(InputEl, message);
break;
}
if ( rule && typeof rule === "function" ) {
rule(vNode.context, InputEl.value, validateError, InputEl);
break;
}
}
校验不符合,执行报错函数
/**
* 执行错误提示函数,用input-error 类名和含有错误信息的p元素表示未通过校验
* @param el: HTMLElement,传入当前绑定的input元素
* @param errorMsg: string,传入错误提示信息
*/
const validateError = (el: HTMLElement, errorMsg: string) => {
if (Array.prototype.includes.call(el.classList, "input-error")) {
//如果当前组件里已经有了错误提示信息,什么也不做
return;
} else {
const errorNode = document.createElement("p");
errorNode.className = "error-tips";
errorNode.textContent = errorMsg;
if (el.parentNode) {
// 在当前input 元素后追加一个p元素,内容为错误提示
el.parentNode.appendChild(errorNode);
}
// 在当前input 元素上添加一个input-error类名
el.className += " input-error";
}
};
现在我就把自己实现的这个表单校验插件大致说完了,下面我们看下具体使用。
3.自定义校验指令v-validateParams使用首先新建校验规则文件:
// rules.ts export const required = (message) => ({ message, required: true }); export const min = (message, length=3) => ({ message, min: length }) export const max = (message, length=15) => ({ message, max: length }) export const pattern = (message, reg) => ({ message, pattern: reg }) // form.vue
通过这个例子我们可以看到,使用时需要将校验规则引入并赋给vue实例中的数据。然后在模板中,需要给input标签添加v-check类名,再使用v-validateParams指令,并传入参数。提交按钮需要调用v-checkSubmit指令。按照这种方式就能够使用自己开发的这个表单校验插件。
4. 当前方式存在的问题虽然表单校验可以使用了,但是存在一些显而易见的问题:
1.js和html耦合度较高,插件还需要获取dom元素,组件的html模板中还需要添加指定的类名。
2.在vue中使用dom操作,不符合vue的设计思路,实现方式也不优雅。
3.校验规则的校验逻辑在指令定义时写定了,添加或删除都需要改动插件代码。
4.提交指令根据当前组件内的是否含有特定dom来判断当前校验状态,且执行提交的函数名称也在指令逻辑中写定了。
我根据现有一个demo结合着自己的需求来实现的这个表单校验插件,开发的过程中我已经知道这么写问题很多,甚至不能称之为一个合格的插件。同时也清楚的认识到自己的javascript水平还很初级,需要很大进步。
当前开发的表单插件的主要问题在于如何将插件中的校验状态返回到组件内。我们可以在插件内维护一个事件处理函数,将校验规则传入并校验,再将校验结果直接传给组件内。这样就可以避免大量的dom操作。之后我需要尽快对这个插件进行更科学合理的重构。
参考文章vue插件
vue自定义指令
vue使用自定义指令实现表单校验
重构:从 0.1 构建一个 Vue 表单验证插件
va.js——Vue 表单验证插件的写作过程
原文链接:tech.gtxlab.com/vue-validat…
作者简介: 宫晨光,人和未来大数据前端工程师。
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/7269.html
摘要:写一个表单验证插件需求目标简单易用可扩展如何简单开发者要做的写了一个表单,指定一个,指定其验证规则。调用提交表单方法,可以获取验证成功后的数据。 写一个vue表单验证插件(vue-validate-easy) 需求 目标:简单易用可扩展 如何简单 开发者要做的 写了一个表单,指定一个name,指定其验证规则。 调用提交表单方法,可以获取验证成功后的数据。 调用重置表单方法重置表单 自...
摘要:写一个表单验证插件需求目标简单易用可扩展如何简单开发者要做的写了一个表单,指定一个,指定其验证规则。调用提交表单方法,可以获取验证成功后的数据。 写一个vue表单验证插件(vue-validate-easy) 需求 目标:简单易用可扩展 如何简单 开发者要做的 写了一个表单,指定一个name,指定其验证规则。 调用提交表单方法,可以获取验证成功后的数据。 调用重置表单方法重置表单 自...
摘要:写一个表单验证插件需求目标简单易用可扩展如何简单开发者要做的写了一个表单,指定一个,指定其验证规则。调用提交表单方法,可以获取验证成功后的数据。 写一个vue表单验证插件(vue-validate-easy) 需求 目标:简单易用可扩展 如何简单 开发者要做的 写了一个表单,指定一个name,指定其验证规则。 调用提交表单方法,可以获取验证成功后的数据。 调用重置表单方法重置表单 自...
摘要:示例电话电话错误信息指示指令对应的表单控件的验证结果。其主要是根据验证的结果进行的值的变换。如果为空值则默认把所有带有验证的空间作为需要验证对象。 cddv vue.js 表单验证插件使用说明 版本:1.0.8-6 获取 github:这里 npm安装 npm i vue-cdd-validator --save yarn安装 yarn add vue-cdd-validator 安装...
摘要:一表单验证模块的构成任何表单验证模块都是由配置校验报错取值这几部分构成的。其实我是想写个指令来完成表单验证的事的。当然表单验证这种是高度定制化的。 前言 前段时间,老大搭好了Vue的开发环境,于是我们愉快地从JQ来到了Vue。这中间做的时候,在表单验证上做的不开心,看到vue的插件章节,感觉自己也能写一个,因此就自己开始写了一个表单验证插件va.js。 当然为什么不找个插件呢? vu...
阅读 3639·2023-04-26 02:07
阅读 3149·2021-09-22 15:55
阅读 2533·2021-07-26 23:38
阅读 3118·2019-08-29 15:16
阅读 2007·2019-08-29 11:16
阅读 1745·2019-08-29 11:00
阅读 3582·2019-08-26 18:36
阅读 3163·2019-08-26 13:32