表单校验是页面开发中非常常见的一类需求,相信每个前端开发人员都有这方面的经验。网上有很多成熟的表单校验框架,虽然按照它们默认的设计,用起来没有多大的问题,但是在实际工作中,表单校验有可能有比较复杂的个性化的需求,使得我们用这些插件的默认机制并不能完成这些功能,所以要根据自己的需要去改造它们(毕竟自己还不到那个写一个完美的校验框架的层次)。我用过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

效果预览

组件实现

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调用时的方式,只用到了前面提到的这两个选项。

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

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();
}
}));

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

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

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相关的逻辑代码中,就看到实际的使用举例:

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

利用jquery.validate以及bootstrap的tooltip开发气泡式的表单校验组件的更多相关文章

  1. Form表单利用Jquery Validate验证以及ajax提交

    #表单利用Jquery验证验证以及ajax提交 概述>详细讲解表单利用Jquery >验证验证以及ajax提交的过程,以及Validate的自定义提示语,非空判断,输入字段的远程ajax验 ...

  2. bootstrap+jQuery.validate表单校验

    谈谈表单校验 这大概是一种惯例,学习前台后台最开始接触的业务都是用户注册和登录.现在社会坚持以人为本的理念,在网站开发过程同样如此.User是我们面对较多的对象,也是较核心的对象.最开始的用户注册和登 ...

  3. 异步提交form的时候利用jQuery validate实现表单验证

    异步提交form的时候利用jQuery validate实现表单验证相信很多人都用过jquery validate插件,非常好用,并且可以通过下面的语句来自定义验证规则    // 电话号码验证    ...

  4. jQuery.validate表单校验+bootstrap

    谈谈表单校验 这大概是一种惯例,学习前台后台最开始接触的业务都是用户注册和登录.现在社会坚持以人为本的理念,在网站开发过程同样如此.User是我们面对较多的对象,也是较核心的对象.最开始的用户注册和登 ...

  5. 简单好用的表单校验插件——jQuery Validate基本使用方法总结

    jquery validate当前最新版本是1.17.0,下载链接是:https://github.com/jquery-validation/jquery-validation/releases/t ...

  6. 【JAVAWEB学习笔记】28_jqueryAjax:json数据结构、jquery的ajax操作和表单校验插件

    Ajax-jqueryAjax 今天内容: 1.json数据结构(重点) 2.jquery的ajax操作(重点) 3.jquery的插件使用   一.json数据结构 1.什么是json JSON(J ...

  7. 2.12 学习总结 之 表单校验插件validate

    一.说在前面 昨天 学习了ajax的相关知识 今天 学习表单校验插件validate, 并使用ajax 自定义校验规则 二.validate 插件 1.网络上有许多成熟的插件共使用者参考,插件就是将j ...

  8. day32(表单校验js和jquery表单校验)

    校验用户名.密码.密码一直性. <style> .error { color: red } .success { color: green } </style> <scr ...

  9. 使用jQuery的validation插件实现表单校验

    前端表单校验: <!DOCTYPE html> <html lang="en"> <head> <meta charset="U ...

随机推荐

  1. Base64 转换 %2B 变 空格 解决

    //此方法转换会转换出错 deString.ServerUrlDecode().Replace(" ", "+") //换此方法完美解决 HttpUtility ...

  2. App测试

    (1)App独特测试点: 客户端兼容性测试:系统版本.不同深度定制的rom.屏幕分辨率.中断测试.安装.卸载.升级.对其他程序的干扰等 需要的一些工具: appnium / lr /  jmeter ...

  3. Code First开发系列之领域建模和管理实体关系

    返回<8天掌握EF的Code First开发>总目录 本篇目录 理解Code First及其约定和配置 创建数据表结构 管理实体关系 三种继承模式 本章小结 自我测试 本篇的源码下载:点击 ...

  4. DRY(Don't Repeat Yourself )原则

    凡是写过一些代码的程序猿都能够意识到应该避免重复的代码和逻辑.我们通过提取方法,提取抽象类等等措施来达到这一目的.我们总能时不时的听到类似这样的话:”把这些公用的类放到shared项目去,别的项目还要 ...

  5. linux系统编程之进程(八):守护进程详解及创建,daemon()使用

    一,守护进程概述 Linux Daemon(守护进程)是运行在后台的一种特殊进程.它独立于控制终端并且周期性地执行某种任务或等待处理某些发生的事件.它不需要用户输入就能运行而且提供某种服务,不是对整个 ...

  6. 跟vczh看实例学编译原理——三:Tinymoe与无歧义语法分析

    文章中引用的代码均来自https://github.com/vczh/tinymoe.   看了前面的三篇文章,大家应该基本对Tinymoe的代码有一个初步的感觉了.在正确分析"print ...

  7. [译]Asp.net MVC 之 Contorllers(一)

    Asp.net MVC contorllers 在Ajax全面开花的时代,ASP.NET Web Forms 开始慢慢变得落后.有人说,Ajax已经给了Asp.net致命一击.Ajax使越来越多的控制 ...

  8. Atitit learn by need 需要的时候学与预先学习知识图谱路线图

    Atitit learn by need 需要的时候学与预先学习知识图谱路线图 1. 体系化是什么 架构 知识图谱路线图思维导图的重要性11.1. 体系就是架构21.2. 只见树木不见森林21.3. ...

  9. Trace Flag

    Trace Flag能够影响Sql Server的行为,主要用于diagnose performance issue,官方解释是: Trace flags are used to temporaril ...

  10. Security5:Execute AS 和 impersonate 权限

    principal 是统称,包括login,user,role等,可以向作为安全主体的用户授予权限,principal分为server level和database level. 登录名是Server ...