使用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.bgiframe.js在IE9下提示INVALID_CHARACTER_ERR错误
Jan 11 Javascript
js实现日历可获得指定日期周数及星期几示例分享(js获取星期几)
Mar 14 Javascript
JavaScript字符串对象substring方法入门实例(用于截取字符串)
Oct 17 Javascript
JavaScript表单验证实例之验证表单项是否为空
Jan 10 Javascript
AngularJS 遇到的小坑与技巧小结
Jun 07 Javascript
全面解析Bootstrap表单样式的使用
Sep 09 Javascript
jQuery 遍历map()方法详解
Nov 04 Javascript
jQuery实现判断控件是否显示的方法
Jan 11 Javascript
详解Angular2 之 结构型指令
Jun 21 Javascript
HTML5开发Kinect体感游戏的实例应用
Sep 18 Javascript
微信小程序实现简单跑马灯效果
May 26 Javascript
vue 实现强制类型转换 数字类型转为字符串
Nov 07 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
php集成套件服务器xampp安装使用教程(适合第一次玩PHP的新手)
2015/06/03 PHP
thinkphp配置文件路径的实现方法
2016/08/30 PHP
PHP异步进程助手async-helper
2018/02/05 PHP
PHP上传文件及图片到七牛的方法
2018/07/25 PHP
Mozilla中显示textarea中选择的文字
2006/09/07 Javascript
jQuery chili图片远处放大插件
2009/11/30 Javascript
JS特殊函数(Function()构造函数、函数直接量)区别介绍
2013/05/19 Javascript
js实现网页收藏功能
2015/12/17 Javascript
javascript实现倒计时跳转页面
2016/01/17 Javascript
利用css+原生js制作简单的钟表
2020/04/07 Javascript
轻松掌握JavaScript中介者模式
2016/08/26 Javascript
jquery自定义表单验证插件
2016/10/12 Javascript
AngularJS过滤器filter用法总结
2016/12/13 Javascript
vue中如何实现变量和字符串拼接
2017/06/19 Javascript
详解webpack+angular2开发环境搭建
2017/06/28 Javascript
jQuery EasyUI的TreeGrid查询功能实现方法
2017/08/08 jQuery
对angularJs中2种自定义服务的实例讲解
2018/09/30 Javascript
Node.js Event Loop各阶段讲解
2019/03/08 Javascript
node使用request请求的方法
2019/12/20 Javascript
深入理解python中的atexit模块
2017/03/07 Python
Python基于identicon库创建类似Github上用的头像功能
2017/09/25 Python
Python实现中一次读取多个值的方法
2018/04/22 Python
python框架django项目部署相关知识详解
2019/11/04 Python
python脚本实现mp4中的音频提取并保存在原目录
2020/02/27 Python
浅谈python量化 双均线策略(金叉死叉)
2020/06/03 Python
详解Python模块化编程与装饰器
2021/01/16 Python
深入剖析HTML5 内联框架iFrame
2016/05/04 HTML / CSS
毕业生自荐信
2013/12/14 职场文书
捐款倡议书
2014/04/14 职场文书
施工安全责任书
2014/04/14 职场文书
10的分与合教学反思
2014/04/30 职场文书
先进基层党组织材料
2014/12/25 职场文书
实习介绍信范文
2015/05/05 职场文书
羊脂球读书笔记
2015/06/30 职场文书
退休职工欢送会致辞
2015/08/01 职场文书
2016年毕业实习心得体会范文
2015/10/09 职场文书