使用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 相关文章推荐
让JavaScript拥有类似Lambda表达式编程能力的方法
Sep 12 Javascript
一个挺有意思的Javascript小问题说明
Sep 26 Javascript
关于图片的预加载过程中隐藏未知的
Dec 19 Javascript
JavaScript页面模板库handlebars的简单用法
Mar 02 Javascript
Kindeditor在线文本编辑器如何过滤HTML
Apr 14 Javascript
Bootstrap字体图标无法正常显示的解决方法
Oct 08 Javascript
Bootstrap和Java分页实例第一篇
Dec 23 Javascript
js保留两位小数方法总结
Jan 31 Javascript
Vue中$refs的用法详解
Jun 24 Javascript
AngularJS中ng-options实现下拉列表的数据绑定方法
Aug 13 Javascript
tracking.js页面人脸识别插件使用方法
Apr 16 Javascript
详解JavaScript修改注册表的方法
Jan 05 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 clearstatcache()函数详解
2010/03/02 PHP
PHP实现过滤各种HTML标签
2015/05/17 PHP
PHP中COOKIES使用示例
2015/07/26 PHP
PHP如何使用Memcached
2016/04/05 PHP
PHP获取当前文件的父目录方法汇总
2016/07/21 PHP
yii2中LinkPager增加总页数和总记录数的实例
2017/08/28 PHP
Javascript常用运算符(Operators)-javascript基础教程
2007/12/14 Javascript
js函数使用技巧之 setTimeout(function(){},0)
2009/02/09 Javascript
jquery.AutoComplete.js中文修正版(支持firefox)
2010/04/09 Javascript
juqery 学习之四 筛选查找
2010/11/30 Javascript
Javascript公共脚本库系列(一): 弹出层脚本
2011/02/24 Javascript
JavaScript 更严格的相等 [译]
2012/09/20 Javascript
基于jquery固定于顶部的导航响应浏览器滚动条事件
2014/11/02 Javascript
深入理解JavaScript系列(30):设计模式之外观模式详解
2015/03/03 Javascript
JavaScript中对JSON对象的基本操作示例
2016/05/21 Javascript
微信小程序 网络请求(GET请求)详解
2016/11/16 Javascript
JS中检测数据类型的几种方式及优缺点小结
2016/12/12 Javascript
layer.js open 隐藏滚动条的例子
2019/09/05 Javascript
如何在selenium中使用js实现定位
2020/08/18 Javascript
Vue通过阿里云oss的url连接直接下载文件并修改文件名的方法
2020/12/25 Vue.js
复制粘贴功能的Python程序
2008/04/04 Python
python控制台显示时钟的示例
2014/02/24 Python
Python脚本文件打包成可执行文件的方法
2015/06/02 Python
Face++ API实现手势识别系统设计
2018/11/21 Python
解决Pyinstaller 打包exe文件 取消dos窗口(黑框框)的问题
2019/06/21 Python
python自动化unittest yaml使用过程解析
2020/02/03 Python
Django Channel实时推送与聊天的示例代码
2020/04/30 Python
python中加背景音乐如何操作
2020/07/19 Python
Tensorflow使用Anaconda、pycharm安装记录
2020/07/29 Python
python openCV自制绘画板
2020/10/27 Python
解决python 在for循环并且pop数组的时候会跳过某些元素的问题
2020/12/11 Python
残疾人创业典型事迹
2014/02/01 职场文书
小班秋游活动方案
2014/02/22 职场文书
一年级班主任工作总结2014
2014/11/08 职场文书
优秀团员自我评价
2015/03/10 职场文书
Android开发 使用文件储存的方式保存QQ密码
2022/04/24 Java/Android