jQuery基础之表单验证

前言

在学习jquery-validate.js时的一些的记录

正文

在使用jquery-validate.js插件时可以做一些初始化配置
在初始化jquery-validate.js对象的时候,将外部的一些配置和该插件内部的一些默认配置合并在一起,如果有相同的配置,前者覆盖后者(默认)的配置

// Constructor for validator
$.validator = function( options, form ) {
    this.settings = $.extend( true, {}, $.validator.defaults, options );
    this.currentForm = form;
    this.init();
};

rules的格式

标准格式是 key为字符串,value为对象字面直接量

rules : {
    username: {
        required: true,
        minlength: 2
   }
}

也可以是
key为字符串,value也为特定的字符串(“required”)

rulus: {
    username: "required"
}

在插件中会将上面格式调整为:{required:true}的形式。从下面代码可以看出对于usernname:”minlength”就不适用了,它会把它变成{minlength:true}这规则明显不合适

// Converts a simple string to a {string: true} rule, e.g., "required" to {required:true}
    normalizeRule: function( data ) {
        if ( typeof data === "string" ) {
            var transformed = {};
            $.each( data.split( /\s/ ), function() {
                transformed[ this ] = true;
            } );
            data = transformed;
        }
        return data;
    }

jquery-validate.js将这些规则解析后放到rules这个对象用以供校验时访问

插件事件监听处理

在指定的元素上添加事件监听

$( this.currentForm )
                .on( "focusin.validate focusout.validate keyup.validate",
                    ":text, [type='password'], [type='file'], select, textarea, [type='number'], [type='search'], " +
                    "[type='tel'], [type='url'], [type='email'], [type='datetime'], [type='date'], [type='month'], " +
                    "[type='week'], [type='time'], [type='datetime-local'], [type='range'], [type='color'], " +
                    "[type='radio'], [type='checkbox'], [contenteditable], [type='button']", delegate )

                // Support: Chrome, oldIE
                // "select" is provided as event.target when clicking a option
                .on( "click.validate", "select, option, [type='radio'], [type='checkbox']", delegate );

上面的监听事件看起来很奇怪,用空格分隔,外加命名空间,如果不了解on的这些使用方法可以参考Query.on() 函数详解。之前focusin,focusout,keyup都是标准事件,之前一直以为focusin与focusout是自定义的事件,这里需要注意一下。
监听函数处理

function delegate( event ) {

                // Set form expando on contenteditable
                if ( !this.form && this.hasAttribute( "contenteditable" ) ) {
                    this.form = $( this ).closest( "form" )[ 0 ];
                }

                var validator = $.data( this.form, "validator" ),
                    eventType = "on" + event.type.replace( /^validate/, "" ),
                    settings = validator.settings;
                if ( settings[ eventType ] && !$( this ).is( settings.ignore ) ) {
                    settings[ eventType ].call( validator, this, event );
                }
            }

在插件中的settings放置了事件处理函数(settings[ eventType ].call( validator, this, event );,也就是在defaults中定义的onfocusin,onfocusout,onkeyup,onclick,highlight,unhighlight事件,因为在defaults中所以可以在外部重写这些事件,做一些定制样式,这点会在最后重新封装一个适合自己的表单校验插件)

自定义事件

现在仔细探究一下这些自定义事件在插件中是如何工作的

先看一下jQuery提供的一个trigger() 方法

trigger() 方法触发被选元素的指定事件类型。

格式:$(selector).trigger(event,[param1,param2,…])

event 必需。规定指定元素要触发的事件。可以使自定义事件(使用 bind() 函数来附加),或者任何标准事件。
[param1,param2,…] 可选。传递到事件处理程序的额外参数。额外的参数对自定义事件特别有用。

注意到了trigger可以触发bind函数绑定的事件(bind现在用on取代),也就是说只要我在on中定义一些自定义的事件,都是可以通过trigger触发

例子-trigger

<!DOCTYPE html>
<html>
<head>
    <title>JQuery-validation demo | Bootstrap</title>

    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css" />

    <script type="text/javascript" src="js/jquery-1.11.1.js"></script>
    <script type="text/javascript" src="js/jquery.validate.js"></script>
</head>
<body>
<div class="listener">
    <input type="text" />
    <p class="validate"></p>
</div>
<script type="text/javascript">
    $(".listener").on("customizeEvent otherEvent",".validate,[type='text']",function() {
        alert("complete some logical codes here");
    })
    $(".validate").trigger("customizeEvent");
    $("[type='text']").trigger("customizeEvent");
    $("[type='text']").trigger("otherEvent");
</script>
</body>
</html>

上面的代码中on的第一个参数有两种事件,使用space隔开(这样两种事件都会绑定指定的事件处理函数),第二个参数指定了可以触发这个自定义事件的一些元素(满足选择器[type=’text’],validate的元素),第三个参数是指定使用trigger触发这些事件时执行的处理函数
在接下来执行事件的触发,从代码中可以看到我选择对两个元素触发了不同的事件。

插件表单submit监听

插件绑定了submit的监听事件(.validate为命名空间),当我们通过$(“form”).submit() 或直接点击type=“submit”(input , button可以指定type=“submit”)触发submit事件时,会执行绑定好的处理函数

例子-绑定submit

this.on( "submit.validate", function( event )

例子-submit处理

// Prevent submit for invalid forms or custom submit handlers
                if ( validator.cancelSubmit ) {
                    validator.cancelSubmit = false;
                    return handle();
                }
                if ( validator.form() ) {   //校验表单成功
                    if ( validator.pendingRequest ) {
                        validator.formSubmitted = true;
                        return false;
                    }
                    return handle();
                } else {
                    validator.focusInvalid();
                    return false;
                }

cancelSubmit

cancelSubmit 是validator对象的成员属性,当满足选择器”:submit”(input,button 的type为submit或者button没有指定类型多数浏览器会把button当做类型为 submit 的按钮)的按钮触发点击事件时,会查看这个按钮上是否包含class为“cancel”或者有formnovalidate=“formnovalidate”属性,如果按钮存在其中一种,那么就不会进行表单校验直接提交form表单(设置validator.cancelSubmit=true)。

validator.form()
使用validator.form()进行表单元素校验,如果为true,判断validator.pendingRequest是否为true,如果是则不提交form,如果false则执行handle函数(handle执行的是submitHandler()的处理)

submitHandler
插件可以在外部配置submitHandler处理函数,它的意思就是在form表单提交时可以做一些额外的处理,并通过返回true,false来决定表单是否提交。

function handle() {   //提交表单
                    var hidden, result;
                    if ( validator.settings.submitHandler ) {
                        if ( validator.submitButton ) {

                            // Insert a hidden input as a replacement for the missing submit button
                            hidden = $( "<input type='hidden'/>" )
                                .attr( "name", validator.submitButton.name )
                                .val( $( validator.submitButton ).val() )
                                .appendTo( validator.currentForm );
                        }
                        result = validator.settings.submitHandler.call( validator, validator.currentForm, event );
                        if ( validator.submitButton ) {

                            // And clean up afterwards; thanks to no-block-scope, hidden can be referenced
                            hidden.remove();
                        }
                        if ( result !== undefined ) {
                            return result;
                        }
                        return false;
                    }
                    return true;
                }

生成一个hidden的input隐藏域,在执行完submitHandler以后移除,没能明白这里的意图。 执行submitHandler后会有一个返回结果(true | false | undefined),如果自定义的submitHandler没有return返回则结果是undefined,这样导致handle()结果为false,表单不会被提交

插件表单校验的规则

email

/^[a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/

url

/^(?:(?:(?:https?|ftp):)?\/\/)(?:\S+(?::\S*)?@)?(?:(?!(?:10|127)(?:\.\d{1,3}){3})(?!(?:169\.254|192\.168)(?:\.\d{1,3}){2})(?!172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2})(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)(?:\.(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)*(?:\.(?:[a-z\u00a1-\uffff]{2,})).?)(?::\d{2,5})?(?:[/?#]\S*)?$/i

时间

!/Invalid|NaN/.test( new Date( value ).toString()

电话号码

/^(?:-?\d+|-?\d{1,3}(?:,\d{3})+)?(?:\.\d+)?$/.test( value );

数字

 /^\d+$/.test( value )

minlength

minlength: function( value, element, param ) {
            var length = $.isArray( value ) ? value.length : this.getLength( value, element );
            return this.optional( element ) || length >= param;
        },

maxlength

maxlength: function( value, element, param ) {
            var length = $.isArray( value ) ? value.length : this.getLength( value, element );
            return this.optional( element ) || length <= param;
        }

rangelength

rangelength: function( value, element, param ) {
            var length = $.isArray( value ) ? value.length : this.getLength( value, element );
            return this.optional( element ) || ( length >= param[ 0 ] && length <= param[ 1 ] );
        }

equalTo

equalTo: function( value, element, param ) {

            // Bind to the blur event of the target in order to revalidate whenever the target field is updated
            var target = $( param );
            if ( this.settings.onfocusout && target.not( ".validate-equalTo-blur" ).length ) {
                target.addClass( "validate-equalTo-blur" ).on( "blur.validate-equalTo", function() {
                    $( element ).valid();
                } );
            }
            return value === target.val();
        }

插件校验配置方式

插件配置校验有几种方式

$.extend(
            {},
            $.validator.classRules( element ),
            $.validator.attributeRules( element ),
            $.validator.dataRules( element ),
            $.validator.staticRules( element )
        ), element );

在class上配置下面几种样式

classRuleSettings: {
        required: { required: true },
        email: { email: true },
        url: { url: true },
        date: { date: true },
        dateISO: { dateISO: true },
        number: { number: true },
        digits: { digits: true },
        creditcard: { creditcard: true }
    }

在属性上配置校验提供的规则
在属性中配置校验规则,如<input type="text" required="true" /> attributeRules方法会将规则添加到插件的rules中,在表单校验时执行rules中的规则校验

使用data-来配置

<input id="temp" type="text" data-rule-require = true />

在插件源码中执行dataRules函数
例子-dataRules

dataRules: function( element ) {
        var rules = {},
            $element = $( element ),
            type = element.getAttribute( "type" ),
            method, value;

        for ( method in $.validator.methods ) {
            value = $element.data( "rule" + method.charAt( 0 ).toUpperCase() + method.substring( 1 ).toLowerCase() );
            this.normalizeAttributeRule( rules, type, method, value );
        }
        return rules;
    }

在data-xx上的数据可以通过jQuery.data获取。使用data有几点需要注意的地方,第一是data获取的数据是经过解析的数据(如0011 获取到的就是11数字),第二是如上面的data-rule-require = true 通过data获取的name是ruleRequire(去掉- ,首字母大写其余小写连接,每个-之间的单词保持小写))

在name中配置

staticRules方法会获取name配置的规则

staticRules: function( element ) {
        var rules = {},
            validator = $.data( element.form, "validator" );

        if ( validator.settings.rules ) {
            rules = $.validator.normalizeRule( validator.settings.rules[ element.name ] ) || {};
        }
        return rules;
    }

表单校验

checkForm是校验form表单中的每一个元素,让element.elements与自身的rules对比 返回false(验证失败)后加入errorMap集合

showErrors 显示errorMap集合的错误信息。

showErrors方法包含了如何显示校验成功或失败的信息的代码

this.vaild() 函数返回了size: function() {return this.errorList.length;} 是否为0,如果为0则校验通过,如果不为0则不通过

form: function() {
            this.checkForm();
            $.extend( this.submitted, this.errorMap );
            this.invalid = $.extend( {}, this.errorMap );
            if ( !this.valid() ) {
                $( this.currentForm ).triggerHandler( "invalid-form", [ this ] );
            }
            this.showErrors();
            return this.valid();
        }

在showErrors方法中执行了提供了错误样式的可选方法,this.settings.showErrors(可重写),defaultShowErrors默认显示

源码-showErrors

showErrors: function( errors ) {
            if ( errors ) {
                var validator = this;

                // Add items to error list and map
                $.extend( this.errorMap, errors );
                this.errorList = $.map( this.errorMap, function( message, name ) {
                    return {
                        message: message,
                        element: validator.findByName( name )[ 0 ]
                    };
                } );

                // Remove items from success list
                this.successList = $.grep( this.successList, function( element ) {
                    return !( element.name in errors );
                } );
            }
            if ( this.settings.showErrors ) {
                this.settings.showErrors.call( this, this.errorMap, this.errorList );
            } else {
                this.defaultShowErrors();
            }
        }

defaultShowErrors方法执行了检验错误元素的highlight显示,校验成功元素的unhighlight显示。需要注意的是defaultShowErrors方法会让错误提示信息全部显示出来this.addWrapper( this.toShow ).show();
该方法中还执行一个比较重要的方法showLabel,在这个方法中可以重写里面的this.settings.errorPlacement 来实现自定义错误信息显示的样式

定制jquery.validate.js

改造方向

  • 校验失败的提示信息
  • 校验信息的提示位置
  • 浮动提示框
  • 鼠标移动到校验失败元素上提示错误信息

1.errorElement:”校验错误面板”包含校验信息需要在外界覆盖
2.自定义校验样式一般重写beginValidate(默认使用插件提供的showErrors方法显示错误信息),easyValidate也重写了showErrors因为默认的showErrors会显示校验错误的信息,即使在beginValidate使用display:none,但是执行到默认的showErrors会使用jQuery.show()显示处理
3.success是在$.validate.setting下,因此可以在外界重写,提供校验成功样式
4.highlight是校验失败元素所执行方法,主要是给边框增加校验失败是的样式,这里是显示红色(样式has-error)
5.unhighlight是校验成功元素所执行方法,和highlight恰恰相反,这里显示绿色(样式has-success)
6.jQuery.extend(jQuery.validator.messages, {}) 重写提示内容,可中文显示提示信息

代码-自定义

/**===============jquery-validate.js自定义样式=======================*/
/**
 * 说明
 * 封装的easyValidate提供便利的同时也存在着局限性,在使用easyValidate的时候需要注意几点
 * 1.每个表单元素需要用一个col-xx-xx包含
 * 2.radio与checkbox需要在外界包含一个div(class为radio),这是由bootstrap提供能够是两种在布局上看起来更加舒适
 * 3. .form-horizontal .has-feedback .form-control-feedback {
    right: 15px;
    }
    页面bootstrap样式不要满足上面的样式,不然叉和钩两个图标排列有问题top:0,right:0 因为父容器存在padding-right:15px,所以会和padding-right内边距对齐,form-horizontal写在form表单上
 * 其他说明
 * 1.errorElement:校验错误面板包含校验信息需要在外界覆盖
 * 2.自定义校验样式一般重写beginValidate(默认使用插件提供的showErrors方法显示错误信息),easyValidate也重写了showErrors
 * 因为默认的showErrors会显示校验错误的信息,即使在beginValidate使用display:none,但是执行到默认的showErrors会使用jQuery.show()显示处理
 * 3.success是在$.validate.setting下,因此可以在外界重写,提供校验成功样式
 * 4.highlight是校验失败元素所执行方法,主要是给边框增加校验失败是的样式,这里是显示红色(样式has-error)
 * 5.unhighlight是校验成功元素所执行方法,和highlight恰恰相反,这里显示绿色(样式has-success)
 */
(function($){
    var easyValidate = function(option) {
        $$this =  new easyValidate.prototype.init();
        $$this.version = '1.0 ';  //插件版本
        return $$this;
    }
    easyValidate.prototype = {      //在原型中定义easyForm的封装方法
        init: function () {  //初始化方法,返回init的this对象
            return this;
        },
        beginValidate:function() {
            jQuery.extend(jQuery.validator.messages, {
                required: "必选字段",
                remote: "请修正该字段",
                email: "请输入正确格式的电子邮件",
                url: "请输入合法的网址",
                date: "请输入合法的日期",
                dateISO: "请输入合法的日期 (ISO).",
                number: "请输入合法的数字",
                digits: "只能输入整数",
                creditcard: "请输入合法的信用卡号",
                equalTo: "请再次输入相同的值",
                accept: "请输入拥有合法后缀名的字符串",
                maxlength: jQuery.validator.format("请输入一个长度最多是 {0} 的字符串"),
                minlength: jQuery.validator.format("请输入一个长度最少是 {0} 的字符串"),
                rangelength: jQuery.validator.format("请输入一个长度介于 {0} 和 {1} 之间的字符串"),
                range: jQuery.validator.format("请输入一个介于 {0} 和 {1} 之间的值"),
                max: jQuery.validator.format("请输入一个最大为 {0} 的值"),
                min: jQuery.validator.format("请输入一个最小为 {0} 的值")
            });

            $("#signupForm").validate({
                errorElement: "div",
                errorPlacement: function ( error, element ) {
                    var validate = this;
                    // Add the `help-block` class to the error element
                    error.addClass( "help-block" ); //目的是让校验失败的字体变红 具体查看.has-error .help-block
                    error.addClass("validate-error panel arrow arrow-left");

                    // Add `has-feedback` class to the parent div.form-group
                    // in order to add icons to inputs
                    element.parents( "[class*=col-]").first().addClass( "has-feedback" );
                    if ( element.prop( "type" ) === "checkbox" ) {
                        error.insertAfter( element.parent( "label" ) );
                    } else {
                        error.insertAfter( element );
                    }
                    // Add the span element, if doesn't exists, and apply the icon classes to it.
                    if ( !element.next( "span" )[ 0 ] ) {
                        $( "<span class='glyphicon glyphicon-remove form-control-feedback'></span>" ).insertAfter( element );
                    }
                    var tempElement = validate.checkable(element.get(0))? element.parents("."+element.get(0).type) : element; //element是jQuery对象,通过get(0)获取dom本身
                    tempElement.off("mouseover").on("mouseover",function(){
                        if(error.parents(".has-error").length!=0) { //如果没有匹配也是一个Object对象,所以用length!=0来判断
                            error.css("display","block");
                        }
                    });
                    tempElement.off("mouseout").on("mouseout",function(){
                        if(error.parents(".has-error").length!=0) {
                            error.css("display","none");
                        }
                    });
                },
                showErrors: function() {
                    var i, elements, error;
                    for ( i = 0; this.errorList[ i ]; i++ ) {
                        error = this.errorList[ i ];
                        if ( this.settings.highlight ) {
                            this.settings.highlight.call( this, error.element, this.settings.errorClass, this.settings.validClass );
                        }
                        this.showLabel( error.element, error.message );
                    }
                    if ( this.errorList.length ) {
                        this.toShow = this.toShow.add( this.containers );
                    }
                    if ( this.settings.success ) {
                        for ( i = 0; this.successList[ i ]; i++ ) {
                            this.showLabel( this.successList[ i ] );
                        }
                    }
                    if ( this.settings.unhighlight ) {
                        for ( i = 0, elements = this.validElements(); elements[ i ]; i++ ) {
                            this.settings.unhighlight.call( this, elements[ i ], this.settings.errorClass, this.settings.validClass );
                        }
                    }
                    this.toHide = this.toHide.not( this.toShow );
                    this.hideErrors();
                },
                success: function ( label, element ) {
                    // Add the span element, if doesn't exists, and apply the icon classes to it.
                    if ( !$( element ).next( "span" )[ 0 ] ) {
                        $( "<span class='glyphicon glyphicon-ok form-control-feedback'></span>" ).insertAfter( $( element ) );
                    }
                },
                /** 校验失败执行的方法,可以添加失败的边框样式*/
                highlight: function ( element, errorClass, validClass ) {
                    $( element ).parents( "[class*=col-]").first().addClass( "has-error" ).removeClass( "has-success" );
                    $( element ).next( "span" ).addClass( "glyphicon-remove" ).removeClass( "glyphicon-ok" );
                },
                /** 校验成功执行的方法,可以添加校验成功的边框样式*/
                unhighlight: function ( element, errorClass, validClass ) {
                    //$( element ).parents( "[class*=col-]")可能会过滤出多个祖父级别的元素,取最近一个
                    $( element ).parents( "[class*=col-]").first().addClass( "has-success" ).removeClass( "has-error" );
                    $( element ).next( "span" ).addClass( "glyphicon-ok" ).removeClass( "glyphicon-remove" );
                    /** 校验成功移除错误信息面板,因为校验错误鼠标移动到所在元素并输入正确字符后变成校验成功,鼠标从校验成功之前就一直在该
                     * 元素上,所以还会存在一个空白面板*/
                    $("."+errorClass).css("display","none");
                }
            });
        }
    }
    easyValidate.prototype.init.prototype = easyValidate.prototype;
    window.easyValidate = easyValidate();
}(jQuery));

效果图
这里写图片描述

使用jquery-validate.js时一些注意的地方

jquery-validate.js只对submit实现监听处理而我自己写的一个针对form提交的插件采用的是jquery-form.js的ajax提交方式。因此需要考虑下面几个问题

生成submit事件
使用$(_this.settings.easyForm).submit();触发submit事件,关于这个jquery.submit()函数需要说明一下:调用几次就会触发submit事件的几次,最后传递到后台的请求只有一次

event.preventDefault();会忽略按钮产生的效果,比如说按钮是type=“submit”,那么就不会自动请求到后台

/** 绑定操作按钮事件,默认是表格的查询按钮*/
            if(this.settings.operationBtn) {
                var _this = this;
                $(this.settings.operationBtn).on("click",function(event){
                    event.preventDefault();
                    event.stopPropagation();
                    $(_this.settings.easyForm).submit();
                    _this.sendRequest2Server();
                });
            }

上面代码需要注意使用submit()生成了submit以后会让三方执行submit的处理函数,第一是当前自己的form事件处理函数(如果按钮是type=’submit’),第二是jquery.validate.js的submit处理函数,第三是jquery.form.js的submit处理
我要做的就是让jquery.validate.js和自己的form表单提交的submit不执行,

jquery.validate.js的submit不执行,重写submitHandler,直接返回false

submitHandler: function(form, event) {
    return false; //校验成功以后不提交
}

使用自己的ajax方法请求到后台(sendRequest2Server,使用的是jquery.form.js),在提交之前使用beforeSubmit 校验数据是否有效

例子-jquery.form.js提交方法

sendRequest2Server:function(extra) { //经过表单校验
    extra = extra || {};
    extra = $.extend({},this.settings.data,extra); //因为默认配置也有一个可能由外部传入的额外数据,这里extra和settings.data合并
    /** beforeSubmit 用来校验表单,将easyForm对象提供回调函数作为上下文,在回调函数直接使用this获取*/                    easyAjax.easyAjaxForm.call(this,this.settings.easyForm,this.settings.requestUrl,extra,this.settings.callback,true,this.verifyForm());
}

在jquery.form.js提供的ajaxSubmit中重写beforeSubmit,进行表单校验
例子-校验

verifyForm: function(formData, jform, options) {
    if(!options.context.easyValidate.isValid()) {
        return false; //easyAjaxForm不会被执行
    }
    //formData是 .serializeArray()返回的数据格式
    options.context.settings.preData = $.param(formData); //记录这一次成功查询的传递数据
    //页面还是显示highlight、unhighlight样式,这里移除
    options.context.easyValidate.resetForm();
}

如果isValid()为false则不提交。如何在自定义插件中判断表单是否有效
在使用$form.validate({})创建jquery-validate对象时将对象赋给this.validate成员属性中,通过这个对象的valid()方法判断表单数据是否有效
例子-表单是否有效

isValid: function() {
    return this.validate.valid();
}

移除jquery.validate.js的校验样式

如果使用ajax提交包含校验内容的表单,在ajax执行成功以后表单样式中还是存在之前的校验的样式
使用jquery.validate.js提供的resetForm可以移除样式,但是却不能移除重写success,highlight,unhighlight的样式。这里在自定义的插件中定义一个方法来调用jquery.validate.js提供的resetForm并在添加移除success,highlight,unhighlight增加的样式

例子-移除样式

    resetForm: function() {
            //移除jquery-validate插件的原有样式
            this.validate.resetForm();
            //移除失败样式
            this.removeHighLight();
            //移除成功样式
            this.removeUnHighLight();
            //移除其它的样式
            $(".has-feedback",this.form).removeClass("has-feedback");
            $("[id$='-error']",this.form).remove(); 
        }

参考资料

jquery.validate.js表单验证

©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页