使用vue自定义指令开发表单验证插件validate.js


Posted in Javascript onMay 23, 2019

这段时间在进行一个新项目的前期搭建,新项目框架采用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
<template>
 <div>
 <div class="form-item">
  <label for="userEmail">用户名:</label>
  <input id="userEmail" class='v-check' type="text" v-model="userName"
  v-validateParams="[inputNameRequired, inputNameMin, inputNameMax, inputNamePattern]">
 </div>
 <button class="btn" v-if="show" type="success" v-checkSubmit>确认</button>
 </div>
</template>
<script lang='ts'>
import { Component, Vue, Prop } from 'vue-property-decorator';
import { max, min, required, name, pattern} from 'rules';

@Component({
 components: {},
})
export default class Auth extends Vue {
 private show: boolean = true;
 private userName: string = '';
 private inputNameMax = max('请不要超过20个字符');
 private inputNameMin = min('请不要小于3个字符');
 private inputNameRequired = required('请输入用户名');
 private inputNamePattern = pattern('请输入符合要求的用户名', /^[a-zA-Z0-9_-]{4,16}$/);
 private submit() {
 alert('通过校验');
 }
}
</script>

通过这个例子我们可以看到,使用时需要将校验规则引入并赋给vue实例中的数据。然后在模板中,需要给 input 标签添加 v-check 类名,再使用 v-validateParams 指令,并传入参数。提交按钮需要调用 v-checkSubmit 指令。按照这种方式就能够使用自己开发的这个表单校验插件。

3. 当前方式存在的问题

虽然表单校验可以使用了,但是存在一些显而易见的问题:

1.js和html耦合度较高,插件还需要获取dom元素,组件的html模板中还需要添加指定的类名。

2.在vue中使用dom操作,不符合vue的设计思路,实现方式也不优雅。

3.校验规则的校验逻辑在指令定义时写定了,添加或删除都需要改动插件代码。

4.提交指令根据当前组件内的是否含有特定dom来判断当前校验状态,且执行提交的函数名称也在指令逻辑中写定了。

我根据现有一个demo结合着自己的需求来实现的这个表单校验插件,开发的过程中我已经知道这么写问题很多,甚至不能称之为一个合格的插件。同时也清楚的认识到自己的javascript水平还很初级,需要很大进步。

当前开发的表单插件的主要问题在于如何将插件中的校验状态返回到组件内。我们可以在插件内维护一个事件处理函数,将校验规则传入并校验,再将校验结果直接传给组件内。这样就可以避免大量的dom操作。之后我需要尽快对这个插件进行更科学合理的重构。

总结

以上所述是小编给大家介绍的使用vue自定义指令开发表单验证插件validate.js,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对三水点靠木网站的支持!

Javascript 相关文章推荐
jQuery Trim去除字符串首尾空字符的实现方法说明
Feb 11 Javascript
js控制网页背景音乐播放与停止的方法
Feb 06 Javascript
纯javascript实现四方向文本无缝滚动效果
Jun 16 Javascript
JQuery zClip插件实现复制页面内容到剪贴板
Nov 02 Javascript
Jsonp 关键字详解及json和jsonp的区别,ajax和jsonp的区别
Dec 30 Javascript
js实现界面向原生界面发消息并跳转功能
Nov 22 Javascript
vue.js的提示组件
Mar 02 Javascript
在Vue中使用axios请求拦截的实现方法
Oct 25 Javascript
js变量声明var使用与不使用的区别详解
Jan 21 Javascript
layui实现数据表格点击搜索功能
Mar 26 Javascript
Layui数据表格判断编辑输入的值,是否为我需要的类型详解
Oct 26 Javascript
JavaScript canvas绘制圆弧与圆形
Feb 18 Javascript
微信小程序开发实现消息推送
Nov 18 #Javascript
jQuery操作attr、prop、val()/text()/html()、class属性
May 23 #jQuery
js打开word文档预览操作示例【不是下载】
May 23 #Javascript
仿iPhone通讯录制作小程序自定义选择组件的实现
May 23 #Javascript
判断js数据类型的函数实例详解
May 23 #Javascript
JS定义函数的几种常用方法小结
May 23 #Javascript
vue-test-utils初使用详解
May 23 #Javascript
You might like
咖啡的传说和历史
2021/03/03 新手入门
PHP文本数据库的搜索方法
2006/10/09 PHP
PHP UTF8中文字符截断函数代码
2012/09/11 PHP
phpmyadmin打开很慢的解决方法
2014/04/21 PHP
PHP接口继承及接口多继承原理与实现方法详解
2017/10/18 PHP
PHP PDOStatement::setAttribute讲解
2019/02/01 PHP
laravel5.1 ajax post 传值_token示例
2019/10/24 PHP
js获得指定控件输入光标的坐标兼容IE,Chrome,火狐等多种主流浏览器
2013/05/21 Javascript
防止jQuery ajax Load使用缓存的方法小结
2014/02/22 Javascript
js网页右下角提示框实例
2014/10/14 Javascript
Css3制作变形与动画效果
2015/07/24 Javascript
快速实现JS图片懒加载(可视区域加载)示例代码
2017/01/04 Javascript
浅谈$_FILES数组为空的原因
2017/02/16 Javascript
如何用JavaScript实现功能齐全的单链表详解
2019/02/11 Javascript
nodejs实现日志读取、日志查找及日志刷新的方法分析
2019/05/20 NodeJs
Vue+Django项目部署详解
2019/05/30 Javascript
vue-simple-uploader上传成功之后的response获取代码
2020/09/07 Javascript
小程序实现录音功能
2020/09/22 Javascript
JavaScript原生数组函数实例汇总
2020/10/14 Javascript
[51:26]VP vs VG 2018国际邀请赛小组赛BO2 第二场 8.19
2018/08/21 DOTA
python操作日期和时间的方法
2014/03/11 Python
Python写的服务监控程序实例
2015/01/31 Python
Python实现获取汉字偏旁部首的方法示例【测试可用】
2018/12/18 Python
Python3显示当前时间、计算时间差及时间加减法示例代码
2019/09/07 Python
在python中修改.properties文件的操作
2020/04/08 Python
Python 如何定义匿名或内联函数
2020/08/01 Python
matplotlib绘制多子图共享鼠标光标的方法示例
2021/01/08 Python
美国在线眼镜商城:Eyeglasses.com
2017/06/26 全球购物
沃达丰英国有限公司:Vodafone英国
2019/04/16 全球购物
Java Servlet API中forward() 与redirect()的区别
2014/04/20 面试题
文员个人求职自荐信
2013/09/21 职场文书
生日宴会答谢词
2014/01/09 职场文书
2014年幼儿园老师工作总结
2014/12/05 职场文书
教师考核表个人总结
2015/02/12 职场文书
《地震中的父与子》教学反思
2016/02/16 职场文书
思想品德课教学反思
2016/02/24 职场文书