基于jQuery.validate及Bootstrap的tooltip开发气泡样式的表单校验组件思路详解


Posted in Javascript onJuly 18, 2016

表单校验是页面开发中非常常见的一类需求,相信每个前端开发人员都有这方面的经验。网上有很多成熟的表单校验框架,虽然按照它们默认的设计,用起来没有多大的问题,但是在实际工作中,表单校验有可能有比较复杂的个性化的需求,使得我们用这些插件的默认机制并不能完成这些功能,所以要根据自己的需要去改造它们(毕竟自己还不到那个写一个完美的校验框架的层次)。我用过formValidation这个校验框架,虽然它跟bootstrap配合地很好,但是校验风格太死板,不太满足个性化的场景;后来我找到了jquery.validate,我发现这个框架还挺好的,因为它只提供校验机制,但是不提供特定校验的交互,有比较多的自定义的空间。在校验风格方面,有很多的形式,可以通过颜色,边框,动画,文本显示,弹框等多种方式来产生交互,至于要用哪种,就由需求以及自己的喜好来决定了。我偏向使用气泡提示的校验风格,因为气泡信息在界面上只显示于字段的周边,而不会对表单的内容有所改变,看起来体验比较好。本文介绍自己使用jquery.validate以及bootstrap的tooltip打造一种气泡式表单校验的思路,如果你有一些个性化较强的表单校验需求,希望这篇文章能对你有些参考价值。

在线demo(点击下面链接页面中的保存按钮,或者改变表单元素的值都能触发校验):

http://liuyunzhuge.github.io/blog/form/dist/html/demo3.html

demo相关的逻辑代码:

https://github.com/liuyunzhuge/blog/blob/master/form/src/js/app/demo3.js

效果预览:

基于jQuery.validate及Bootstrap的tooltip开发气泡样式的表单校验组件思路详解

组件实现:

https://github.com/liuyunzhuge/blog/blob/master/form/src/js/mod/formValidation.js

https://github.com/liuyunzhuge/blog/tree/master/form/src/js/mod/validation

(有3个关联的文件,可通过以上链接查看)

其它事项:

1)本文提供的校验实现依赖jquery,jquery.validate,bootstrap,并采用seajs来做模块化管理;

2)本文的demo结合之前写的form组件来一起使用,form管理的相关文章有:

简洁易用的表单数据设置和收集管理组件

进一步丰富和简化表单管理的组件:form.js

相关文档:

1)jquery.validate使用说明 : https://jqueryvalidation.org/documentation/

2)tootip使用说明: http://v3.bootcss.com/javascript/#tooltips

下面就来看看该如何实现这个气泡式的表单校验吧。

1. 实现思路

用过jquery.validate就知道,这个插件默认的校验机制是在某一个表单元素校验失败后,把校验失败的信息用一个label元素包裹起来,然后插入到表单元素的后面。如果我们要换成气泡式的校验,那么首先就要考虑把它默认的插入失败信息的label元素的机制给取消掉,因为有了气泡,这个label显然是多余的;然后还要去修改它的校验控制逻辑,在元素校验失败的时候,用气泡组件显示失败信息,在校验成功的时候,移除可能存在的相关的气泡组件(因为这个元素之前如果有校验失败的情况,就会初始化相关的气泡组件)。至于这两个动作该怎么去处理,简单的方法就是改源码,但是改源码会带来更大的问题,一是不利于升级,二是不利于扩展,将来要做其它的个性化校验,就容易冲突。更好地办法是去查阅官方文档,找到最佳的api来做自定义,这样的话,就能完全避免改源码带来的问题。如果我们碰到改造一个已有的组件来完成另一个组件,并且不得不改源码的情况,更好的方式,不是直接把另一个组件的逻辑写到已有的组件里面,而是在已有的组件里面添加合适的接口,再通过接口来完成另一个组件。

翻阅jquery.validate的文档,可以了解到它最核心的api是validate这个方法,这是一个可以直接在jquery对象上调用的方法,在调用它的时候,可以通过option传递很多的选项,其中有两个选项,就可以用来完成我们的自定义功能:errorPlacement与showErrors,这两个方法的作用以及签名分别是:

errorPlacement : function(error, element) {…}

用来自定义表单元素失败信息的插入位置,如果这个方法是一个空函数,那么失败信息就不会插入到DOM里面去。它有两个参数,error表示失败信息生成的jquery对象;element表示单个的表单元素的jquery对象。

showErrors: function(errorMap, errorList) {…}

用来自定义校验信息的显示机制。它有两个参数,第一个参数以Object的形式,封装了当前校验操作的所有校验失败的信息;第二个参数errorList是一个数组,它的每个元素包含两个属性element和message分别代表失败的表单元素的jq对象和失败信息。另外在这个方法里面通过this.successList还可访问到所有校验成功的元素列表,这个successList也是一个数组,它的每个元素就是校验成功的表单元素的DOM对象。

通过前面对这两个方法的描述,大概就能知道该如何去完成自定义的表单校验功能了:

1)如果在errorPlacement这个option里什么都不做,那么校验的时候就不会插入到页面中了;

2)在showErrors里面,通过errorList和successList,我们可以分别遍历一遍,给失败的元素显示tooltip,然后给成功的元素移除tooltip。

下图是简单说明我的实现中对jquery.validate调用时的方式,只用到了前面提到的这两个选项。

基于jQuery.validate及Bootstrap的tooltip开发气泡样式的表单校验组件思路详解

接下来就来看看实际实现时的一些要点。

2. 详细实现

1)从代码组织说起

本文实现主要包含三个文件:

https://github.com/liuyunzhuge/blog/blob/master/form/src/js/mod/formValidation.js

https://github.com/liuyunzhuge/blog/tree/master/form/src/js/mod/validation(这个文件包含两个文件:validate.js和validator.js)

核心的文件是mod/validation文件夹下的两个。其中:

validate.js是最核心的代码,包含了所有的自定义逻辑; validator.js仅仅是对jquery.validate默认的校验信息做的重置,因为它默认是英文的,而我的项目环境不需要考虑英文,所以就在这个文件里做了统一的处理;另外如果要添加一些全局的校验器的话,也可以考虑添加在这里。

mod/formValidation.js是在页面中直接引用的文件,它依赖mod/validation/validate.js,同时基于validate.js提供的接口,注册了一些自定义的处理,这些自定义的处理我会在后面进行说明,它的作用仅仅是为了将validate.js的功能与我之前写的form相关组件结合起来使用。

如果你对本文的实现感兴趣,但是对我写的form相关组件不感兴趣的话,完全可以考虑只关注validate.js和validator.js,因为没有formValidation.js,它们的功能依然是完整的。

2)新添加的option

在validate.js中可以看到有一个DEFAULTS,来定义本文实现的组件模块的option,除了对jquery.validate插件相关的option进行覆盖,还增加了以下option,来完成更丰富的功能:

useTooltip: true,//配置是否启用气泡提示来显示校验失败的信息,默认启用
tipPlacement: 'right',//全局的气泡提示的位置
tooltipDuration: 2500,//多久自动隐藏tooltip
fieldConfig: {},//按字段名称配置一些东西,如:
/**
 * {
 * title: {
 * fvTipTarget: function($field){ return $field.closest(...);}, //配置气泡提示关联的DOM元素
 * tipPlacement: 'top', //配置气泡提示的显示位置:上下左右
 * tooltipClass: 'tooltip-name', //配置气泡提示组件需要添加的css类
 * errorPlacement: function(error,element){}, //配置字段错误信息的插入位置
 * fvRelatedTarget: function($field){return ...}, //配置校验时关联影响的DOM元素
 * }
 * }
 *
 * 其中fvTipTarget fvRelatedTarget可以是function和jQuery对象两种形式
 */
fieldTypeConfig: {},//按字段类型配置一些东西,如:
/**
 * {
 * date: {
 * fvTipTarget: function($field){ return $field.closest(...);}, //配置date类型的字段校验失败时气泡提示关联的DOM元素
 * tipPlacement: 'top', //配置date类型的字段校验失败时气泡提示的显示位置:上下左右
 * tooltipClass: 'tooltip-name', //配置date类型的字段校验失败时气泡提示组件需要添加的css类
 * errorPlacement: function(error,element){}, //配置date类型的字段的错误信息的插入位置
 * fvRelatedTarget: function($field){return ...}, //配置date类型的字段时校验时关联影响的DOM元素
 * }
 * }
 * 如果要为所有的类型定义一个配置,可把类型名称设置为all,如all: {errorPlacement: function(){..}}
 * 优先级:
 * fieldConfig > fieldTypeConfig<type> > Validation.defaultFieldTypeConfig > fieldTypeConfig<all>
 */

详细作用如下:

useTooltip决定了是否启用气泡校验的功能,默认为true,如果为false,validate.js提供的模块将使用默认的校验机制来显示校验逻辑;

tipPlacement: 全局的气泡提示显示的位置,用过bootstrap的tooltip就知道,它可以显示到一个元素的上下左右,通过这个可以改变气泡提示的默认位置;

tooltipDuration: 配置气泡显示的时间。我提供的实现,在显示气泡时的逻辑是:在校验失败的时候,显示tootip,然后在这个选项指定的时间过去之后,自动消失,当鼠标再次移入失败元素的时候,tooltip会再次显示,鼠标移出的时候再消失。

fieldConfig:可以用来根据字段名称做一些配置,注释中有配举例。可配置的选项说明如下:

- fvTipTarget:用来自定义气泡显示在哪个元素上; - tipPlacement:配置某个元素气泡提示的显示位置 - tooltipClass:自定义气泡组件的css类 - errorPlacement:自定义某个元素的失败信息的插入位置 - fvRelatedTarget:自定义元素校验时需要关联影响的其它元素,其实就是在表单元素校验失败的时候也把相关的validClass和errorClass这两个css类,同步管理到其它元素而已。

需要注意的是,fieldConfig是根据字段元素名称来配置的,因为只能根据名称来找到相应的元素,所以表单元素上面一定要有name属性,这样才能找到fieldConfig中的配置项。

fieldTypeConfig:可以用来按字段类型做一些配置,它的配置项跟fieldConfig的一致,只不过它的好处在于,可以为同一个类型的字段指定相同的配置,省的在fieldConfig里面要重复配置。

需要注意的是:fieldType是通过在表单元素上的type属性或者data-type属性或者data-fv-type属性来指定的,优先级:data-fv-type > data-type > type。在fieldTypeConfig中,可以使用all这个特殊的type,它不需要在表单元素上指定,用来对所有的字段进行一个统一的配置。在validate.js模块的静态成员上,提供了defaultFieldTypeConfig对象,通过扩展这个对象,可以提供默认的一些按字段类型的配置,方便做一些统一处理。最后一点在静态成员部分还会再详细介绍。

jquery.validate相关的一些需要覆盖的option及其说明如下:

debug: true,//防止校验成功后表单自动提交
submitHandler: $.noop,//屏蔽表单校验成功后的表单提交功能,由外部的Form组件负责提交
ignore: '[type="hidden"]:not(.fv-yes),[disabled]:not(.fv-yes),.fv-no',//用于过滤不参与校验的元素
errorElement: 'i',//使用<i>元素来包裹校验失败的信息
errorClass: 'fv-error',//校验失败时相应的class
validClass: 'fv-valid'//校验成功时相应的class

需要补充的是:

a. 为啥要防止表单自动提交,因为我自己更偏向于主动控制表单提交;

b. ignore部分,没有完全把隐藏的或者禁用的表单元素排除掉,有一些时候隐藏元素也是能够用于校验的。

3)核心实现

核心实现的方法就是下面的代码:

$element.validate($.extend(opts, {
 errorPlacement: function (error, element) {
 if (opts.useTooltip) {
  return;
 }
 //jquery.validate组件默认的校验失败信息的插入方式是:在该元素后面插入校验失败的信息
 //我们可以按字段及字段类型通过fieldConfig与fieldTypeConfig来自定义插入的方式
 var _errorPlacement = getCommonConfig('errorPlacement', element, opts);
 if (!isFunc(_errorPlacement)) {
  _errorPlacement = function () {
  error.insertAfter(element);
  }
 }
 _errorPlacement(error, element);
 },
 showErrors: function (errorMap, errorList) {
 //覆盖这个方法以便在校验失败的时候显示tooltip
 //不启用tooltip的时候按默认的方式显示失败信息
 var successList = this.successList;
 //处理本次校验失败的字段
 if ($.isArray(errorList)) {
  errorList.forEach(function (item) {
  setRelatedTargetStyle(item.element, opts, true);
  if (opts.useTooltip) {
   //显示失败的tooltip
   showErrorItem(item, opts, that);
  }
  });
 }
 if ($.isArray(successList)) {
  successList.forEach(function (element) {
  setRelatedTargetStyle(element, opts, false);
  if (opts.useTooltip) {
   //移除原先可能失败导致的tooltip
   showSuccessItem(element, opts, that);
  }
  });
 }
 //官方文档要求,在自定义showErrors之后,通过调用下面的方法完全内置的其它处理
 this.defaultShowErrors();
 }
}));

这两个代码应该很好理解,因为各个部分的逻辑都已经单独抽出来封装了,细节可以逐一去阅读了解:

基于jQuery.validate及Bootstrap的tooltip开发气泡样式的表单校验组件思路详解

以上每个方法都比较简单,所以就不拆开来介绍了。

4)继承jquery.validate提供的其它api方法

由于在实际的工作中,表单校验的逻辑有的时候会很复杂,尤其涉及到字段有增删改,校验规则有增删改的时候,所以去看jquery.valiate的文档,也能发现它提供了不止validate这个api,还有很多其它有用的方法,为了方便,所以直接把jquery.validate提供的其它validate.js不具备的方法都继承过来:

//将jquery.validate的api方法代理到自身
for (var i in this._validator) {
 if (!(i in this) && isFunc(this._validator[i])) {
 this[i] = (function (context, func) {
  return function () {
  return func.apply(context, arguments);
  }
 })(this._validator, this._validator[i]);
 }
}

5)表单校验重置

一个很普遍的需求,就是有的时候需要重置表单,这个时候除了重置表单元素的值,还得重置它们的校验状态,虽然jquery.validate有提供相关方法,但是由于我们有用到tooltip组件以及添加了一些其它处理,所以需要对表单校验的重置功能,做一些自定义,主要是tooltip组件的销毁和一些状态的还原:

resetForm: function () {
 var $element = this.$element,
 opts = this.options;
 //清除掉tooltip组件及绑定的事件
 if (opts.useTooltip) {
 $element.find('.fv-tip-target').each(function () {
  var tooltip = $(this).data('bs.tooltip');
  checkHideTimeout(tooltip);
  tooltip && tooltip.destroy();
 }).off('.fv');
 }
 $element.find('.fv-related-target').removeClass(opts.validClass + ' fv-related-target ' + opts.errorClass);
 this._validator.resetForm();
}

6)静态成员

validate.js提供了一些静态成员,有属性也有方法,使用的方法见mod/formValidation.js。其中

defaultFieldTypeConfig:用来存储全局的一些按字段类型的配置项;

extendFieldTypeConfig:用来扩展defaultFieldTypeConfig。

validateEvents:用来存储全局的一些自定义的校验事件。

addValidateEvent和removeValidateEvent用来添加和移除自定义的校验事件。

为什么会有自定义的校验事件?因为在jquery.validate这个插件的默认机制下,有些表单元素的change事件并不会触发当前元素的校验,导致界面上不能实时反馈元素的校验状态。这个用来帮助我们自动的注册一些元素的特殊事件,然后在这些事件回调内主动触发对元素的校验。

3. 使用举例

从demo相关的逻辑代码中,就看到实际的使用举例:

基于jQuery.validate及Bootstrap的tooltip开发气泡样式的表单校验组件思路详解

基于jQuery.validate及Bootstrap的tooltip开发气泡样式的表单校验组件思路详解

从这个举例也能看到,新的Validation组件跟直接使用jquery.validate没有太大的区别,就是多几个option,rules跟messages都是jquery.validate提供的option,而fieldTypeConfig是新提供的option;但是在功能上,校验的方式已经完全变成我所期待的的气泡式校验了,这个体验跟jquery.validate默认的体验比起来,肯定就要好很多了。

4. 相关CSS

为了正确显示demo中的校验效果,css也是很重要的一部分,demo相关的css可在src/css/form.css中去查找,跟校验相关的css可通过.fv这个关键词来搜索。

5. 总结

本文介绍了一种如何根据jquery.validate这种已有的校验框架来完成个性化的表单校验功能思路,将来在碰到其它的个性化校验需求的时候,也完全可参照这个思路,尝试去做些统一的自定义组件,毕竟基于已有的成果去扩展比自己去造轮子,要来的更快更轻一些。本文提供的校验方式,使用起来还是挺爽的,也支持校验规则的增删改,方式同官方文档,欢迎使用并讨论相关的问题,我在项目中都用它,尤其在管理系统里面开发的时候,非常高效。

以上所述希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对三水点靠木网站的支持!

Javascript 相关文章推荐
javascript Math.random()随机数函数
Nov 04 Javascript
jQuery CSS()方法改变现有的CSS样式
Aug 20 Javascript
js实现Select下拉框具有输入功能的方法
Feb 06 Javascript
JavaScript动态添加style节点的方法
Jun 09 Javascript
JavaScript计划任务后台运行的方法
Dec 18 Javascript
HTML5游戏引擎LTweenLite实现的超帅动画效果(附demo源码下载)
Jan 26 Javascript
JavaScript中字符串的常用操作方法及特殊字符
Mar 18 Javascript
vue+mousemove实现鼠标拖动功能(拖动过快失效问题解决方法)
Aug 24 Javascript
详解关于Vue2.0路由开启keep-alive时需要注意的地方
Sep 18 Javascript
优雅的在React项目中使用Redux的方法
Nov 10 Javascript
JS sort方法基于数组对象属性值排序
Jul 10 Javascript
Vue中Object.assign清空数据报错的解决方案
Mar 03 Vue.js
javascript时间差插件分享
Jul 18 #Javascript
如何用js实现鼠标向上滚动时浮动导航
Jul 18 #Javascript
终于实现了!精彩的jquery弹幕效果
Jul 18 #Javascript
全面解析JavaScript中“&amp;&amp;”和“||”操作符(总结篇)
Jul 18 #Javascript
全面介绍javascript实用技巧及单竖杠
Jul 18 #Javascript
Bootstrap 布局组件(全)
Jul 18 #Javascript
js验证真实姓名与身份证号,手机号的简单实例
Jul 18 #Javascript
You might like
php面向对象全攻略 (六)__set() __get() __isset() __unset()的用法
2009/09/30 PHP
使用Thinkphp框架开发移动端接口
2015/08/05 PHP
php resizeimage 部分jpg文件 生成缩略图失败的原因分析及解决办法
2016/03/23 PHP
用js实现上传图片前的预览(TX的面试题)
2007/08/14 Javascript
JavaScript的类型转换(字符转数字 数字转字符)
2010/08/30 Javascript
Jquery中的CheckBox、RadioButton、DropDownList的取值赋值实现代码
2011/10/12 Javascript
利用jquery动画特效和css打造的侧边弹出垂直导航
2014/04/04 Javascript
当滚动条滚动到页面底部自动加载增加内容的js代码
2014/05/13 Javascript
node.js中的fs.writeFile方法使用说明
2014/12/14 Javascript
javascript包装对象实例分析
2015/03/27 Javascript
详解JavaScript编程中正则表达式的使用
2015/10/25 Javascript
jQuery Ajax 加载数据时异步显示加载动画
2016/08/01 Javascript
AngularJS获取json数据的方法详解
2017/05/27 Javascript
jQuery EasyUI的TreeGrid查询功能实现方法
2017/08/08 jQuery
带你快速理解javascript中的事件模型
2017/08/14 Javascript
浅谈Vue服务端渲染框架Nuxt的那些事
2018/12/21 Javascript
vue+Element实现搜索关键字高亮功能
2019/05/28 Javascript
微信自定义分享链接信息(标题,图片和内容)实现过程详解
2019/09/04 Javascript
Vue.js 中制作自定义选择组件的代码附演示demo
2020/02/28 Javascript
Ant Design moment对象和字符串之间的相互转化教程
2020/10/27 Javascript
Python实现的二维码生成小软件
2014/07/11 Python
python的类方法和静态方法
2014/12/13 Python
Python中urllib+urllib2+cookielib模块编写爬虫实战
2016/01/20 Python
python装饰器初探(推荐)
2016/07/21 Python
python3实现表白神器
2019/04/09 Python
浅谈python多进程共享变量Value的使用tips
2019/07/16 Python
python2与python3爬虫中get与post对比解析
2019/09/18 Python
python如果快速判断数字奇数偶数
2019/11/13 Python
pytorch 批次遍历数据集打印数据的例子
2019/12/30 Python
tensorflow指定GPU与动态分配GPU memory设置
2020/02/03 Python
基于python检查矩阵计算结果
2020/05/21 Python
使用ITK-SNAP进行抠图操作并保存mask的实例
2020/07/01 Python
python中altair可视化库实例用法
2021/01/26 Python
大学军训通讯稿
2014/01/13 职场文书
七一讲话心得体会
2014/09/05 职场文书
生日寿星公答谢词
2015/09/29 职场文书