├── .gitignore ├── README.md ├── demo.html.url ├── demo ├── css │ ├── button.css │ ├── common.css │ ├── demo.css │ ├── form.css │ ├── reset.css │ └── validate.css ├── iconfont │ ├── demo.css │ ├── demo.html │ ├── iconfont.css │ ├── iconfont.eot │ ├── iconfont.svg │ ├── iconfont.ttf │ └── iconfont.woff ├── images │ └── select_arrow.png ├── jq-validate.html ├── js │ ├── jquery-mvalidate.js │ └── zepto-mvalidate.js ├── libs │ └── zepto.all.js ├── php │ ├── captcha.php │ ├── captchaAjax1.php │ ├── captchaAjax2.php │ ├── form.php │ └── phoneCode.php ├── valid-phonecode.html ├── validate-captcha1.html ├── validate-captcha2.html └── zepto-validate.html ├── dist ├── css │ └── validate.css └── js │ ├── jquery-mvalidate.js │ └── zepto-mvalidate.js ├── gruntfile.js ├── package.json └── src ├── css └── validate.css └── js ├── jquery-mvalidate.js └── zepto-mvalidate.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/* 2 | .git -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # mobileValidate 2 | mobileValidate是一款针对移动端的表单验证控件,充分考虑到移动端屏幕和空间大小的情况下,它提供了两种表单的验证提示方式,基本满足日常表单的验证需求!查看demo 3 | 4 | ## 目录 5 | 6 | * [特性](#特性) 7 | * [调用方式](#调用方式) 8 | * [参数](#参数) 9 | * [拓展方法](#拓展方法) 10 | 11 | ## 特性 12 | 13 | 1. 通过 data-* 的方式来来决定表单是否需要验证,验证类型 14 | 2. 通过 mvalidateExtend 方法提供自定义拓展验证方式 15 | 3. 不同于其他的表单验证,该控件在用户初次输入的时候(keyup事件)是不进行验证的,这样的方式更符合用户的使用习惯 16 | 17 | ## 调用方式 18 |
19 | $(form).mvalidate({
20 |     type:1,
21 |     validateInSubmit:true
22 | })
23 | 
24 | 25 | ## 参数 26 | 参数 | 类型 | 描述 | 默认值 27 | ------------ | ------------- | ------------ | ------------ 28 | type | Number | 验证类型,类型1:弹出提示信息,类型2:未通过验证的表单下面显示提示文字 | 1 29 | validateInSubmit | Boolean | 点击"提交"按钮的时候是否要对表单进行验证 | true 30 | sendForm | Boolean | 表单通过验证的时候,是否需要提交表单 | true 31 | onKeyup | Boolean | 输入放开键盘的时候,是否需要验证 | false 32 | firstInvalidFocus | Boolean | 未通过验证的第一个表单元素,是否要获取焦点 | true 33 | conditional | Object | 输入域通过data-conditional="name"对应到conditional中属性等于name的函数 | {} 34 | descriptions | Object | 输入域通过data-descriptions="name"对应到descriptions中属性名等于name的函数 | {} 35 | eachField | Function | 输入域在执行验证之前触发该函数| {} 36 | eachInvalidField | Function | 所有未通过验证的表单输入域触发该函数 | $.noop 37 | eachValidField | Function | 所有的通过验证的表单输入域触发该函数 | $.noop 38 | valid | Function | 点击“提交”按钮的时候,若表单通过验证,就触发该函数! | $.noop 39 | invalid | Function | 点击“提交”按钮的时候,若表单未通过验证,就触发该函数! | $.noop 40 | 41 | ## 拓展方法 42 | 方法| 描述 43 | ------------ | ------------- 44 | $.mvalidateExtend | 该方法用来拓展一些输入域的验证,例如:data-validate="phone" 45 |
46 | $.mvalidateExtend({
47 |     phone:{
48 |         required : true,   
49 |         pattern : /^0?1[3|4|5|8][0-9]\d{8}$/,
50 |         each:function(){
51 |            
52 |         },
53 |         descriptions:{
54 |             required : '必填字段',
55 |             pattern : '请您输入正确的格式'
56 |         }
57 |     }
58 | });
59 | 
60 | 61 | 62 | 63 | 64 | 65 | 66 | -------------------------------------------------------------------------------- /demo.html.url: -------------------------------------------------------------------------------- 1 | [{000214A0-0000-0000-C000-000000000046}] 2 | Prop3=19,2 3 | [InternetShortcut] 4 | IDList= 5 | URL=http://wnworld.com/mobilevalidate 6 | -------------------------------------------------------------------------------- /demo/css/button.css: -------------------------------------------------------------------------------- 1 | /** 2 | * -webkit-user-select:禁止选中复制; 3 | * touch-action:移除特定元素或整个文档的触发延迟 4 | */ 5 | .zbtn { 6 | display: inline-block; 7 | padding: 6px 12px; 8 | margin-bottom: 0; 9 | font-size: 14px; 10 | font-weight: normal; 11 | line-height: 1.42857143; 12 | text-align: center; 13 | white-space: nowrap; 14 | vertical-align: middle; 15 | -ms-touch-action: manipulation; 16 | touch-action: manipulation; 17 | cursor: pointer; 18 | -webkit-user-select: none; 19 | -moz-user-select: none; 20 | -ms-user-select: none; 21 | user-select: none; 22 | background-image: none; 23 | border: 1px solid transparent; 24 | border-radius: 4px; 25 | } 26 | 27 | /** 28 | * 注意button的状态:选中active focus blur 29 | * 30 | * .zbtn:focus 给有foucs的html标签是用 31 | * :focus 有
39 | 40 | 41 |
42 |
43 | 44 |
45 |
46 | 47 | 48 | 49 | 50 | 114 | 115 | 116 | 117 | -------------------------------------------------------------------------------- /demo/validate-captcha1.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | ZUI -表单验证控件 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 18 | 19 | 20 | 21 |
22 | 23 |

表单验证控件

24 |
25 |
验证类型1
26 |
27 |
28 |
29 |
30 |
31 | 32 |
33 |
34 |
35 |
36 | 37 |
38 |
39 |
40 |
41 | 42 |
43 |
44 |
45 |
46 | 47 |
48 |
49 |
50 |
51 | 52 |
53 |
54 |
55 |
56 | 61 |
62 |
63 |
64 | 65 |
66 | 67 |
68 |
69 |
70 | 71 |
72 | 75 | 78 | 81 | 84 |
85 |
86 |
87 | 88 |
89 | 92 | 95 |
96 |
97 |
98 | 99 |
100 | 101 |
102 |
103 | 104 | 看不清 105 |
106 |
107 |
108 | 109 |
110 |
111 | 112 | 113 | 114 | 115 | 209 | 210 | -------------------------------------------------------------------------------- /demo/validate-captcha2.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | ZUI -表单验证控件 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 20 | 21 | 22 | 23 |
24 | 25 |

表单验证控件

26 |
27 | 28 |
验证类型2
29 |
30 |
31 |
32 |
33 |
34 | 35 |
36 |
37 |
38 |
39 |
40 | 41 |
42 |
43 |
44 |
45 |
46 | 47 |
48 |
49 |
50 |
51 |
52 | 53 |
54 |
55 |
56 |
57 |
58 | 59 |
60 |
61 |
62 |
63 |
64 | 69 |
70 |
71 |
72 |
73 | 74 |
75 | 76 |
77 |
78 |
79 |
80 | 81 |
82 | 85 | 88 | 91 | 94 |
95 |
96 |
97 |
98 | 99 |
100 | 103 | 106 |
107 |
108 |
109 |
110 | 111 |
112 | 113 |
114 |
115 | 116 | 看不清 117 |
118 |
119 |
120 |
121 | 122 |
123 |
124 | 125 | 126 | 240 | 241 | -------------------------------------------------------------------------------- /demo/zepto-validate.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | ZUI -表单验证控件 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 |

表单验证控件

21 |
22 |
验证类型1
23 |
24 |
25 |
26 |
27 |
28 | 29 |
30 |
31 |
32 |
33 | 34 |
35 |
36 |
37 |
38 | 39 |
40 |
41 |
42 |
43 | 44 |
45 |
46 |
47 |
48 | 49 |
50 |
51 |
52 |
53 | 58 |
59 |
60 |
61 | 62 |
63 | 64 |
65 |
66 |
67 | 68 |
69 | 72 | 75 | 78 | 81 |
82 |
83 |
84 | 85 |
86 | 89 | 92 |
93 |
94 |
95 | 96 |
97 |
98 |
验证类型2
99 |
100 |
101 |
102 |
103 |
104 | 105 |
106 |
107 |
108 |
109 |
110 | 111 |
112 |
113 |
114 |
115 |
116 | 117 |
118 |
119 |
120 |
121 |
122 | 123 |
124 |
125 |
126 |
127 |
128 | 129 |
130 |
131 |
132 |
133 |
134 | 139 |
140 |
141 |
142 |
143 | 144 |
145 | 146 |
147 |
148 |
149 |
150 | 151 |
152 | 155 | 158 | 161 | 164 |
165 |
166 |
167 |
168 | 169 |
170 | 173 | 176 |
177 |
178 |
179 |
180 | 181 |
182 |
183 | 184 |
查看文档
185 | 321 | 322 | 323 | Status API Training Shop Blog About 324 | © 2016 GitHub, Inc. Terms Privacy Security Contact Help -------------------------------------------------------------------------------- /dist/css/validate.css: -------------------------------------------------------------------------------- 1 | .field-invalid{border-color:#a94442}.field-invalidmsg{color:#a94442}.field-validmsg{color:#3c763d}.field-tooltipWrap{position:absolute;left:0;top:0;width:100%;z-index:19891014}.field-tooltipInner{pointer-events:none;display:table;position:fixed;left:0;top:0;width:100%;height:100%}.field-tooltip{display:table-cell;vertical-align:middle;text-align:center}.field-tooltip .field-invalidmsg,.field-tooltip .field-validmsg{color:#fff}.field-tooltip .zvalid-resultformat{display:inline-block;position:relative;background-color:rgba(0,0,0,.8);color:#fff;padding:10px 15px;font-size:14px;border-radius:6px;box-shadow:0 0 8px rgba(0,0,0,.1);pointer-events:auto;animation-name:fieldTipBounceIn;-webkit-animation-name:fieldTipBounceIn;-webkit-animation-fill-mode:both;animation-fill-mode:both;-webkit-animation-duration:.18s;animation-duration:.18s}@-webkit-keyframes fieldTipBounceIn{0%{opacity:0;-webkit-transform:scale3d(.3,.3,.3);transform:scale3d(.3,.3,.3)}100%{opacity:1;-webkit-transform:scale3d(1,1,1);transform:scale3d(1,1,1)}}@keyframes{0%{opacity:0;-webkit-transform:scale3d(.3,.3,.3);transform:scale3d(.3,.3,.3)}100%{opacity:1;-webkit-transform:scale3d(1,1,1);transform:scale3d(1,1,1)}} -------------------------------------------------------------------------------- /dist/js/jquery-mvalidate.js: -------------------------------------------------------------------------------- 1 | /*! 2 | 版本:1.0.0; 3 | 作者:散崖; 4 | 邮箱:948061564@qq.com; 5 | 博客地址:http://wnworld.com/;*/ 6 | !function(a){"function"==typeof define&&define.amd?define(["jquery"],function(b){a(b)}):"function"==typeof define&&define.cmd?define(["jquery"],function(b,c,d){a(b("jquery"))}):a(jQuery)}(function(a){var b=['input:not([type]),input[type="color"],input[type="date"],input[type="datetime"],input[type="datetime-local"],input[type="email"],input[type="file"],input[type="hidden"],input[type="month"],input[type="number"],input[type="password"],input[type="range"],input[type="search"],input[type="tel"],input[type="text"],input[type="time"],input[type="url"],input[type="week"],textarea',"select",'input[type="checkbox"],input[type="radio"]'],c=b.join(","),d={},e=function(a,b,c){if("radio"==a.prop("type")||"checkbox"==a.prop("type")){var d=c.$form.find('[name="'+a.prop("name")+'"]');d.filter(":checked").length>0?d.removeClass("field-invalid"):d.addClass("field-invalid")}else b.required&&b.pattern&&b.conditional?a.removeClass("field-invalid"):a.addClass("field-invalid")},f=function(){function b(b){if(!c){var d=a('
'+b+"
");d.appendTo(a("body")),c=!0,setTimeout(function(){d.remove(),c=!1},1500)}}var c=null;return{show:b}}(),g=function(c,g){var h,i=a(this),j={required:!0,conditional:!0,pattern:!0},k=a.fn.mvalidate.errorTipFormat,l=a.trim(i.val())||"",m=i.attr("data-validate"),n=void 0!=m?d[m]:{},o=i.attr("data-required"),p=i.attr("data-pattern")||("regexp"==a.type(n.pattern)?n.pattern:/(?:)/),q=i.attr("data-conditional")||n.conditional,r=i.attr("data-descriptions")||n.descriptions,s=i.attr("data-describedby")||n.describedby;r=a.isPlainObject(r)?r:g.descriptions[r]||{},o=""==o||(o||!!n.required),"regexp"!=a.type(p)&&(p=RegExp(p)),o&&(i.is(b[0]+","+b[1])?!l.length>0&&(j.required=!1):i.is(b[2])&&(i.is("[name]")?0==g.$form.find('[name="'+i.prop("name")+'"]:checked').length&&(j.required=!1):j.required=field.is(":checked"))),i.is(b[0])&&(p.test(l)||(o?j.pattern=!1:l.length>0&&(j.pattern=!1))),"undefined"!=q&&(a.isFunction(q)?j.conditional=!!q.call(i,l,g):g.conditional.hasOwnProperty(q)&&!g.conditional[q].call(i,l,g)&&(j.conditional=!1)),h=k(r.valid),j.required?j.pattern?j.conditional||(h=k(r.conditional)):h=k(r.pattern):h=k(r.required);var t=a('[id="'+s+'"]');return t.length>0&&2==g.type&&("keyup"!=c.type&&"change"!=c.type||t.children().length&&a.trim(t.text()))&&(t.html(h||""),e(i,j,g)),"function"==typeof n.each&&n.each.call(i,c,j,g),g.eachField.call(i,c,j,g),j.required&&j.pattern&&j.conditional?("function"==typeof n.valid&&n.valid.call(i,c,j,g),g.eachValidField.call(i,c,j,g)):(!g.firstInvalid&&g.firstInvalidFocus&&(g.firstInvalid=!0,i.focus()),1==g.type&&f.show(h),"function"==typeof n.invalid&&n.invalid.call(i,c,j,g),g.eachInvalidField.call(i,c,j,g)),j};a.extend(a,{mvalidateExtend:function(b){return a.extend(d,b)},mvalidateTip:function(b){var c=a.fn.mvalidate.errorTipFormat(b);f.show(c)}}),a.fn.mvalidate=function(d){var e,f={type:1,validateInSubmit:!0,sendForm:!0,onKeyup:!1,onChange:!0,firstInvalidFocus:!0,conditional:{},descriptions:{},eachField:a.noop,eachValidField:a.noop,eachInvalidField:a.noop,valid:a.noop,invalid:a.noop,namespace:"mvalidate"},h=a.extend(!0,f,d),i=h.namespace;return h.type=Number(h.type),h.firstInvalid=!1,e=1!=h.type,this.mvalidateDestroy().each(function(d){var f,j=a(this);j.is("form")&&(h.$form=j,j.data(name,{options:h}),f=j.find(c),e&&h.onKeyup&&f.filter(b[0]).each(function(){a(this).on("keyup."+i,function(a){g.call(this,a,h)})}),e&&h.onChange&&f.each(function(){a(this).is(b[1]+","+b[2])&&a(this).on("change."+i,function(a){g.call(this,a,h)})}),h.validateInSubmit&&j.on("submit."+i,function(b){var c=!0;h.firstInvalid=!1,f.each(function(){var a=g.call(this,b,h);a.pattern&&a.conditional&&a.required||(c=!1)}),c?(h.sendForm||b.preventDefault(),a.isFunction(h.valid)&&h.valid.call(j,b,h)):(b.preventDefault(),b.stopImmediatePropagation(),a.isFunction(h.invalid)&&h.invalid.call(j,b,h))}))})},a.fn.mvalidateDestroy=function(){var b,d=a(this),e="mvalidate",f=d.data(e);return f?(d.is("form")&&a.isPlainObject(f)&&"string"==typeof f.options.nameSpace&&(b=d.removeData(name).find(c),b.off("."+f.options.nameSpace)),d):d},a.fn.mvalidate.errorTipFormat=function(a){return'
'+a+"
"}}); -------------------------------------------------------------------------------- /dist/js/zepto-mvalidate.js: -------------------------------------------------------------------------------- 1 | /*! 2 | 版本:1.0.0; 3 | 作者:散崖; 4 | 邮箱:948061564@qq.com; 5 | 博客地址:http://wnworld.com/;*/ 6 | !function(a){"function"==typeof define&&define.amd?define(["Zepto"],function(b){a(b)}):"function"==typeof define&&define.cmd?define(["Zepto"],function(b,c,d){a(b("Zepto"))}):a(Zepto)}(function(a){var b=['input:not([type]),input[type="color"],input[type="date"],input[type="datetime"],input[type="datetime-local"],input[type="email"],input[type="file"],input[type="hidden"],input[type="month"],input[type="number"],input[type="password"],input[type="range"],input[type="search"],input[type="tel"],input[type="text"],input[type="time"],input[type="url"],input[type="week"],textarea',"select",'input[type="checkbox"],input[type="radio"]'],c=b.join(","),d={},e=function(a,b,c){if("radio"==a.prop("type")||"checkbox"==a.prop("type")){var d=c.$form.find('[name="'+a.prop("name")+'"]');d.filter(":checked").length>0?d.removeClass("field-invalid"):d.addClass("field-invalid")}else b.required&&b.pattern&&b.conditional?a.removeClass("field-invalid"):a.addClass("field-invalid")},f=function(){function b(b){if(!c){var d=a('
'+b+"
");d.appendTo(a("body")),c=!0,setTimeout(function(){d.remove(),c=!1},1500)}}var c=null;return{show:b}}(),g=function(c,g){var h,i=a(this),j={required:!0,conditional:!0,pattern:!0},k=a.fn.mvalidate.errorTipFormat,l=a.trim(i.val())||"",m=i.attr("data-validate"),n=void 0!=m?d[m]:{},o=i.attr("data-required"),p=i.attr("data-pattern")||("regexp"==a.type(n.pattern)?n.pattern:/(?:)/),q=i.attr("data-conditional")||n.conditional,r=i.attr("data-descriptions")||n.descriptions,s=i.attr("data-describedby")||n.describedby;r=a.isPlainObject(r)?r:g.descriptions[r]||{},o=""==o||(o||!!n.required),"regexp"!=a.type(p)&&(p=RegExp(p)),o&&(i.is(b[0]+","+b[1])?!l.length>0&&(j.required=!1):i.is(b[2])&&(i.is("[name]")?0==g.$form.find('[name="'+i.prop("name")+'"]:checked').length&&(j.required=!1):j.required=field.is(":checked"))),i.is(b[0])&&(p.test(l)||(o?j.pattern=!1:l.length>0&&(j.pattern=!1))),"undefined"!=q&&(a.isFunction(q)?j.conditional=!!q.call(i,l,g):g.conditional.hasOwnProperty(q)&&!g.conditional[q].call(i,l,g)&&(j.conditional=!1)),h=k(r.valid),j.required?j.pattern?j.conditional||(h=k(r.conditional)):h=k(r.pattern):h=k(r.required);var t=a('[id="'+s+'"]');return t.length>0&&2==g.type&&("keyup"!=c.type&&"change"!=c.type||t.children().length&&a.trim(t.text()))&&(t.html(h||""),e(i,j,g)),"function"==typeof n.each&&n.each.call(i,c,j,g),"function"==typeof g.eachField&&g.eachField.call(i,c,j,g),j.required&&j.pattern&&j.conditional?("function"==typeof n.valid&&n.valid.call(i,c,j,g),g.eachValidField.call(i,c,j,g)):(!g.firstInvalid&&g.firstInvalidFocus&&(g.firstInvalid=!0,i.focus()),1==g.type&&f.show(h),"function"==typeof n.invalid&&n.invalid.call(i,c,j,g),"function"==typeof g.eachInvalidField&&g.eachInvalidField.call(i,c,j,g)),j};a.extend(a,{mvalidateExtend:function(b){return a.extend(d,b)}}),a.fn.mvalidate=function(d){var e,f={type:1,validateInSubmit:!0,sendForm:!0,onKeyup:!1,onChange:!0,firstInvalidFocus:!0,conditional:{},descriptions:{},eachField:a.noop,eachValidField:a.noop,eachInvalidField:a.noop,valid:a.noop,invalid:a.noop,namespace:"mvalidate"},h=a.extend(!0,f,d),i=h.namespace;return h.type=Number(h.type),h.firstInvalid=!1,e=1!=h.type,this.mvalidateDestroy().each(function(d){var f,j=a(this);j.is("form")&&(h.$form=j,j.data(i,{options:h}),f=j.find(c),e&&h.onKeyup&&f.filter(b[0]).each(function(){a(this).on("keyup."+i,function(a){g.call(this,a,h)})}),e&&h.onChange&&f.each(function(){a(this).is(b[1]+","+b[2])&&a(this).on("change."+i,function(a){g.call(this,a,h)})}),h.validateInSubmit&&j.on("submit."+i,function(b){var c=!0;h.firstInvalid=!1,f.each(function(){var a=g.call(this,b,h);a.pattern&&a.conditional&&a.required||(c=!1)}),c?(h.sendForm||b.preventDefault(),a.isFunction(h.valid)&&h.valid.call(j,b,h)):(b.preventDefault(),b.stopImmediatePropagation(),a.isFunction(h.invalid)&&h.invalid.call(j,b,h))}))})},a.fn.mvalidateDestroy=function(){var b,d=a(this),e="mvalidate",f=d.data(e);return f?(d.is("form")&&a.isPlainObject(f)&&"string"==typeof f.options.namespace&&(b=d.removeData(name).find(c),b.off("."+f.options.namespace)),d):d},a.fn.mvalidate.errorTipFormat=function(a){return'
'+a+"
"}}); -------------------------------------------------------------------------------- /gruntfile.js: -------------------------------------------------------------------------------- 1 | module.exports = function (grunt) { 2 | grunt.initConfig({ 3 | pkg: grunt.file.readJSON('package.json'), 4 | cssmin: { 5 | minify:{ 6 | expand:true, 7 | cwd:"demo/css", 8 | src:["validate.css"], 9 | dest:"dist/css", 10 | ext:".css" 11 | } 12 | }, 13 | uglify:{ 14 | options: { 15 | banner: '/*! \n版本:<%= pkg.version %>;\n作者:<%= pkg.author.name %>;\n邮箱:<%= pkg.author.email %>;\n博客地址:<%= pkg.author.blog %>;*/\n' 16 | }, 17 | my_target: { 18 | files:[ 19 | {'dist/js/jquery-mvalidate.js': ['demo/js/jquery-mvalidate.js']}, 20 | {'dist/js/zepto-mvalidate.js': ['demo/js/zepto-mvalidate.js']} 21 | ] 22 | } 23 | }, 24 | copy:{ 25 | my_target: { 26 | files:[ 27 | {expand:true,src:["demo/css/validate.css"],dest:"src/css",flatten:true}, 28 | {expand:true,src:["demo/js/*.js"],dest:"src/js",flatten:true} 29 | ] 30 | } 31 | } 32 | }); 33 | require('load-grunt-tasks')(grunt); 34 | grunt.registerTask("default",['cssmin:minify',"uglify:my_target","copy:my_target"]); 35 | } -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "mvalidate", 3 | "version": "1.0.0", 4 | "description": "移动端的验证控件", 5 | "author": { 6 | "name": "散崖", 7 | "email": "948061564@qq.com", 8 | "blog": "http://wnworld.com/" 9 | }, 10 | "devDependencies": { 11 | "grunt": "^0.4.5", 12 | "load-grunt-tasks": "~0.3.0", 13 | "grunt-contrib-connect": "^0.7.1", 14 | "grunt-contrib-watch": "^0.6.1", 15 | "connect-livereload": "^0.5.2", 16 | "grunt-contrib-concat": "^0.5.0", 17 | "grunt-contrib-cssmin": "^0.11.0", 18 | "grunt-contrib-copy": "^0.7.0", 19 | "grunt-contrib-uglify": "^0.7.0", 20 | "grunt-contrib-jshint": "^0.11.0", 21 | "grunt-contrib-less": "^1.0.0", 22 | "grunt-contrib-clean": "^0.6.0" 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/css/validate.css: -------------------------------------------------------------------------------- 1 | .field-invalid{ 2 | border-color:#a94442; 3 | } 4 | .field-invalidmsg{ 5 | color:#a94442; 6 | } 7 | .field-validmsg{ 8 | color:#3c763d; 9 | } 10 | .field-tooltipWrap{ 11 | position: absolute; 12 | left: 0; 13 | top: 0; 14 | width: 100%; 15 | z-index: 19891014; 16 | } 17 | .field-tooltipInner{ 18 | pointer-events: none; 19 | display: table; 20 | position:fixed; 21 | left:0; 22 | top:0; 23 | width:100%; 24 | height:100%; 25 | } 26 | .field-tooltip{ 27 | display: table-cell; 28 | vertical-align: middle; 29 | text-align: center; 30 | } 31 | .field-tooltip .field-invalidmsg, 32 | .field-tooltip .field-validmsg{ 33 | color: #fff; 34 | } 35 | .field-tooltip .zvalid-resultformat{ 36 | display: inline-block; 37 | position: relative; 38 | background-color:rgba(0,0,0,0.8); 39 | color: #fff; 40 | padding: 10px 15px; 41 | font-size: 14px; 42 | border-radius: 6px; 43 | box-shadow: 0 0 8px rgba(0,0,0,.1); 44 | pointer-events: auto; 45 | animation-name:fieldTipBounceIn; 46 | -webkit-animation-name:fieldTipBounceIn; 47 | -webkit-animation-fill-mode: both; 48 | animation-fill-mode: both; 49 | -webkit-animation-duration: .18s; 50 | animation-duration: .18s; 51 | } 52 | 53 | @-webkit-keyframes fieldTipBounceIn{ 54 | 55 | 0% { 56 | opacity: 0; 57 | -webkit-transform: scale3d(.3, .3, .3); 58 | transform: scale3d(.3, .3, .3); 59 | } 60 | 100% { 61 | opacity: 1; 62 | -webkit-transform: scale3d(1, 1, 1); 63 | transform: scale3d(1, 1, 1); 64 | } 65 | } 66 | 67 | 68 | @keyframes 69 | 70 | { 71 | 72 | 73 | 0% { 74 | opacity: 0; 75 | -webkit-transform: scale3d(.3, .3, .3); 76 | transform: scale3d(.3, .3, .3); 77 | } 78 | 100% { 79 | opacity: 1; 80 | -webkit-transform: scale3d(1, 1, 1); 81 | transform: scale3d(1, 1, 1); 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /src/js/jquery-mvalidate.js: -------------------------------------------------------------------------------- 1 | (function (factory) { 2 | if (typeof define === 'function' && define.amd) { 3 | define(['jquery'], function (jquery) { 4 | // 返回构造函数 5 | factory(jquery); // 初始化插件 6 | }); 7 | } else if (typeof define === 'function' && define.cmd) { 8 | define(['jquery'], function (require, exports, moudles) { 9 | factory( 10 | require('jquery')); // 初始化插件 11 | }) 12 | } else { 13 | factory(jQuery); 14 | } 15 | })(function ($) { 16 | var type = ['input:not([type]),input[type="color"],input[type="date"],input[type="datetime"],input[type="datetime-local"],input[type="email"],input[type="file"],input[type="hidden"],input[type="month"],input[type="number"],input[type="password"],input[type="range"],input[type="search"],input[type="tel"],input[type="text"],input[type="time"],input[type="url"],input[type="week"],textarea', 'select', 'input[type="checkbox"],input[type="radio"]'], 17 | allTypes = type.join(","), 18 | extend = {}; 19 | var fieldValidTypeHand = function ($field, status, options) { 20 | if ($field.prop("type") == "radio" || $field.prop("type") == "checkbox") { 21 | var $fields = options.$form.find('[name="' + $field.prop('name') + '"]'); 22 | 23 | if ($fields.filter(":checked").length > 0) { 24 | $fields.removeClass('field-invalid') 25 | } else { 26 | $fields.addClass('field-invalid') 27 | } 28 | } else { 29 | if (status.required && status.pattern && status.conditional) { 30 | $field.removeClass('field-invalid'); 31 | } else { 32 | $field.addClass('field-invalid'); 33 | } 34 | } 35 | }; 36 | var fieldTooltip = (function () { 37 | var instance = null; 38 | 39 | function show(text) { 40 | if (!instance) { 41 | var $container = $('
' + text + '
'); 42 | $container.appendTo($("body")); 43 | instance = true; 44 | setTimeout(function () { 45 | $container.remove(); 46 | instance = false; 47 | }, 1500) 48 | } 49 | } 50 | 51 | return { 52 | show: show 53 | } 54 | })(); 55 | var validateField = function (event, options) { 56 | var $field = $(this), 57 | status = { 58 | required: true, 59 | conditional: true, 60 | pattern: true 61 | }, 62 | log, //验证提示信息存储变量 63 | 64 | errorTipFormat = $.fn.mvalidate.errorTipFormat, //错误信息输出的格式化 65 | 66 | fieldValue = $.trim($field.val()) || "", 67 | 68 | //*****获取当前字段的data-validate 69 | fieldValidate = $field.attr("data-validate"), 70 | validation = (fieldValidate != undefined) ? extend[fieldValidate] : {}, 71 | //*****获取当前字段的data-required 72 | fieldRequired = $field.attr("data-required"), 73 | //*****获取当前字段的data-pattern 74 | fieldPattern = ($field.attr('data-pattern') || ($.type(validation.pattern) == 'regexp' ? validation.pattern : /(?:)/)), 75 | 76 | 77 | //*****获取当前字段的data-conditional 78 | fieldConditional = $field.attr("data-conditional") || validation.conditional, 79 | //*****获取当前字段的data-description 80 | fieldDescription = $field.attr("data-descriptions") || validation.descriptions, 81 | //*****获取当前字段的data-describedby 82 | fieldDescribedby = $field.attr("data-describedby") || validation.describedby; 83 | 84 | fieldDescription = $.isPlainObject(fieldDescription) ? fieldDescription : (options.descriptions[fieldDescription] || {}); 85 | fieldRequired = fieldRequired != '' ? (fieldRequired || !!validation.required) : true; 86 | if ($.type(fieldPattern) != 'regexp') { 87 | fieldPattern = RegExp(fieldPattern); 88 | } 89 | 90 | //如果是必填验证,那么就要判断是什么类型的表单 91 | if (fieldRequired) { 92 | //如果是那种可以通过val()来判断的 93 | if ($field.is(type[0] + ',' + type[1])) { 94 | if (!fieldValue.length > 0) { 95 | status.required = false; 96 | } 97 | //如果是raido和checkbox,通过name和checked来判断 98 | } else if ($field.is(type[2])) { 99 | if ($field.is('[name]')) { 100 | if (options.$form.find('[name="' + $field.prop('name') + '"]:checked').length == 0) { 101 | status.required = false; 102 | } 103 | } else { 104 | status.required = field.is(':checked'); 105 | } 106 | } 107 | } 108 | /**如果是正则验证 109 | * 只有那些类似type=text的文本框我们才能通过正则表达式去验证pattern, 110 | * 而对于select,radio,checkbox pattern显然是无效的 111 | */ 112 | if ($field.is(type[0]) && status.required) { 113 | //如果不匹配 114 | if (!fieldPattern.test(fieldValue)) { 115 | if (fieldRequired) { 116 | status.pattern = false; 117 | } else { 118 | if (fieldValue.length > 0) { 119 | status.pattern = false; 120 | } 121 | } 122 | } 123 | } 124 | 125 | //如果是data-conditional="name"函数验证,函数返回true或者是false 126 | if (fieldConditional != "undefined" && status.pattern) { 127 | if ($.isFunction(fieldConditional)) { 128 | status.conditional = !!fieldConditional.call($field, fieldValue, options); 129 | } else { 130 | if (options.conditional.hasOwnProperty(fieldConditional) && !options.conditional[fieldConditional].call($field, fieldValue, options)) { 131 | status.conditional = false; 132 | } 133 | } 134 | } 135 | 136 | 137 | //验证通过的信息所在对象 138 | 139 | log = errorTipFormat(fieldDescription.valid); 140 | if (!status.required) { 141 | log = errorTipFormat(fieldDescription.required); 142 | 143 | } else if (!status.pattern) { 144 | log = errorTipFormat(fieldDescription.pattern); 145 | 146 | 147 | } else if (!status.conditional) { 148 | log = errorTipFormat(fieldDescription.conditional); 149 | } 150 | 151 | var $describedShowElem = $('[id="' + fieldDescribedby + '"]'); 152 | //如果找打提示的容器,是第二种类型的验证 153 | if ($describedShowElem.length > 0 && options.type == 2) { 154 | //如果是change 或者是keyup 同时是第一次输入的时候就不要验证 155 | if ((event.type == "keyup" || event.type == "change") && (!$describedShowElem.children().length || !$.trim($describedShowElem.text()))) { 156 | 157 | } else { 158 | $describedShowElem.html(log || ''); 159 | fieldValidTypeHand($field, status, options) 160 | } 161 | } 162 | 163 | if (typeof (validation.each) == 'function') { 164 | validation.each.call($field, event, status, options); 165 | } 166 | options.eachField.call($field, event, status, options); 167 | 168 | if (status.required && status.pattern && status.conditional) { 169 | 170 | if (typeof (validation.valid) == 'function') { //二外拓展的 171 | validation.valid.call($field, event, status, options); 172 | } 173 | options.eachValidField.call($field, event, status, options); 174 | } else { //验证未通过 175 | if (!options.firstInvalid && options.firstInvalidFocus) { 176 | options.firstInvalid = true; 177 | $field.focus(); 178 | } 179 | if (options.type == 1) { 180 | fieldTooltip.show(log) 181 | } 182 | if (typeof (validation.invalid) == 'function') { 183 | validation.invalid.call($field, event, status, options); 184 | } 185 | options.eachInvalidField.call($field, event, status, options); 186 | } 187 | 188 | /** 189 | * 如果是data-describedby="elemId"验证信息要显示的地方,类型3的验证: 190 | * 第一元素获取焦点,keyUp的时候要一直验证,如果正确那么错误信息就隐藏,如果不正确,那么错误 191 | * 提示信息要根据状态而改变,对于与验证通过,那么可以通过eachInvalid来让用户自定义,而无需要 192 | * 在插件中写它的操作方式 193 | */ 194 | return status; 195 | }; 196 | $.extend($, { 197 | mvalidateExtend: function (options) { 198 | return $.extend(extend, options); 199 | }, 200 | mvalidateTip: function (text) { 201 | var txt = $.fn.mvalidate.errorTipFormat(text); 202 | fieldTooltip.show(txt) 203 | } 204 | }); 205 | 206 | 207 | 208 | 209 | 210 | $.fn.mvalidate = function (options) { 211 | var defaults = { 212 | type: 1, 213 | validateInSubmit: true, 214 | sendForm: true, 215 | onKeyup: false, 216 | onChange: true, 217 | firstInvalidFocus: true, //第一个未通过验证的表单是否获得交代呢 218 | conditional: {}, 219 | descriptions: {}, 220 | eachField: $.noop, 221 | eachValidField: $.noop, 222 | eachInvalidField: $.noop, 223 | valid: $.noop, 224 | invalid: $.noop, 225 | namespace: "mvalidate" 226 | }, 227 | opts = $.extend(true, defaults, options), 228 | flag, 229 | namespace = opts.namespace; 230 | 231 | opts.type = Number(opts.type); 232 | opts.firstInvalid = false; 233 | flag = opts.type == 1 ? false : true; 234 | return this.mvalidateDestroy().each(function (event) { 235 | 236 | var $form = $(this), 237 | $fields; //存放当前表单下的所有元素; 238 | if (!$form.is("form")) return; 239 | opts.$form = $form; 240 | $form.data(name, { 241 | "options": opts 242 | }); 243 | $fields = $form.find(allTypes); 244 | 245 | // 246 | if (flag && opts.onKeyup) { 247 | $fields.filter(type[0]).each(function () { 248 | 249 | $(this).on("keyup." + namespace, function (event) { 250 | validateField.call(this, event, opts) 251 | }) 252 | }); 253 | } 254 | 255 | if (flag && opts.onChange) { 256 | $fields.each(function () { 257 | var $this = $(this); 258 | if ($this.is(type[1] + ',' + type[2])) { 259 | $(this).on('change.' + namespace, function (event) { 260 | validateField.call(this, event, opts); 261 | }) 262 | } 263 | }) 264 | } 265 | 266 | //如果需要验证的时候,在提交表单的时候对所有的字段进行验证 267 | if (opts.validateInSubmit) { 268 | $form.on("submit." + namespace, function (event) { 269 | var formValid = true; 270 | opts.firstInvalid = false; 271 | $fields.each(function () { 272 | var status = validateField.call(this, event, opts); 273 | if (!status.pattern || !status.conditional || !status.required) { 274 | formValid = false; 275 | } 276 | }); 277 | 278 | if (formValid) { 279 | if (!opts.sendForm) { 280 | event.preventDefault(); 281 | } 282 | if ($.isFunction(opts.valid)) { 283 | opts.valid.call($form, event, opts); 284 | } 285 | //验证没有通过,禁用提交事件,以及绑定在这个elem上的其他事件 286 | } else { 287 | event.preventDefault(); 288 | event.stopImmediatePropagation(); 289 | if ($.isFunction(opts.invalid)) { 290 | opts.invalid.call($form, event, opts) 291 | } 292 | } 293 | 294 | }) 295 | } 296 | }) 297 | }; 298 | $.fn.mvalidateDestroy = function () { 299 | var $form = $(this), 300 | $fields, namespace = "mvalidate", 301 | dataValidate = $form.data(namespace); 302 | 303 | if (!dataValidate) { 304 | return $form; 305 | } 306 | if ($form.is('form') && $.isPlainObject(dataValidate) && typeof (dataValidate.options.nameSpace) == 'string') { 307 | $fields = $form.removeData(name).find(allTypes); 308 | $fields.off('.' + dataValidate.options.nameSpace); 309 | } 310 | return $form; 311 | }; 312 | $.fn.mvalidate.errorTipFormat = function (text) { 313 | return '
' + text + '
'; 314 | } 315 | 316 | 317 | }) -------------------------------------------------------------------------------- /src/js/zepto-mvalidate.js: -------------------------------------------------------------------------------- 1 | (function (factory) { 2 | if (typeof define === 'function' && define.amd ) { 3 | define(['Zepto'], function(zepto){ 4 | // 返回构造函数 5 | factory(zepto); // 初始化插件 6 | }); 7 | }else if(typeof define === 'function' && define.cmd){ 8 | define(['Zepto'], function(require,exports,moudles){ 9 | factory(require('Zepto')); // 初始化插件 10 | }) 11 | }else{ 12 | factory(Zepto); 13 | } 14 | })(function($){ 15 | var type = ['input:not([type]),input[type="color"],input[type="date"],input[type="datetime"],input[type="datetime-local"],input[type="email"],input[type="file"],input[type="hidden"],input[type="month"],input[type="number"],input[type="password"],input[type="range"],input[type="search"],input[type="tel"],input[type="text"],input[type="time"],input[type="url"],input[type="week"],textarea', 'select', 'input[type="checkbox"],input[type="radio"]'], 16 | allTypes=type.join(","), 17 | extend={}; 18 | var fieldValidTypeHand=function($field,status,options){ 19 | if($field.prop("type")=="radio" || $field.prop("type")=="checkbox"){ 20 | var $fields=options.$form.find('[name="'+$field.prop('name')+'"]'); 21 | 22 | if($fields.filter(":checked").length > 0){ 23 | $fields.removeClass('field-invalid') 24 | }else{ 25 | $fields.addClass('field-invalid') 26 | } 27 | }else{ 28 | if(status.required && status.pattern && status.conditional) { 29 | $field.removeClass('field-invalid'); 30 | }else{ 31 | $field.addClass('field-invalid'); 32 | } 33 | } 34 | }; 35 | var fieldTooltip=(function(){ 36 | var instance=null; 37 | function show(text){ 38 | if(!instance){ 39 | var $container=$('
'+text+'
'); 40 | $container.appendTo($("body")); 41 | instance=true; 42 | setTimeout(function(){ 43 | $container.remove(); 44 | instance=false; 45 | },1500) 46 | } 47 | } 48 | 49 | return { 50 | show:show 51 | } 52 | })(); 53 | var validateField=function(event,options){ 54 | var $field=$(this), 55 | status={ 56 | required:true, 57 | conditional:true, 58 | pattern:true 59 | }, 60 | log,//验证提示信息存储变量 61 | 62 | errorTipFormat=$.fn.mvalidate.errorTipFormat,//错误信息输出的格式化 63 | 64 | fieldValue =$.trim($field.val()) || "", 65 | 66 | //*****获取当前字段的data-validate 67 | fieldValidate=$field.attr("data-validate"), 68 | validation=(fieldValidate != undefined) ? extend[fieldValidate]:{}, 69 | //*****获取当前字段的data-required 70 | fieldRequired=$field.attr("data-required"), 71 | //*****获取当前字段的data-pattern 72 | fieldPattern = ($field.attr('data-pattern') || ($.type(validation.pattern) == 'regexp' ? validation.pattern : /(?:)/)), 73 | 74 | 75 | //*****获取当前字段的data-conditional 76 | fieldConditional=$field.attr("data-conditional") || validation.conditional, 77 | //*****获取当前字段的data-description 78 | fieldDescription=$field.attr("data-descriptions") || validation.descriptions, 79 | //*****获取当前字段的data-describedby 80 | fieldDescribedby=$field.attr("data-describedby") || validation.describedby; 81 | 82 | fieldDescription = $.isPlainObject(fieldDescription) ? fieldDescription : (options.descriptions[fieldDescription] || {}); 83 | fieldRequired=fieldRequired !='' ? (fieldRequired || !!validation.required ) : true; 84 | if($.type(fieldPattern) != 'regexp') { 85 | fieldPattern=RegExp(fieldPattern); 86 | } 87 | 88 | //如果是必填验证,那么就要判断是什么类型的表单 89 | if(fieldRequired) { 90 | //如果是那种可以通过val()来判断的 91 | if($field.is(type[0] + ',' + type[1])) { 92 | if(!fieldValue.length > 0){ 93 | status.required = false; 94 | } 95 | //如果是raido和checkbox,通过name和checked来判断 96 | }else if($field.is(type[2])){ 97 | if($field.is('[name]')) { 98 | if(options.$form.find('[name="'+$field.prop('name')+'"]:checked').length==0){ 99 | status.required = false; 100 | } 101 | }else{ 102 | status.required = field.is(':checked'); 103 | } 104 | } 105 | } 106 | /**如果是正则验证 107 | * 只有那些类似type=text的文本框我们才能通过正则表达式去验证pattern, 108 | * 而对于select,radio,checkbox pattern显然是无效的 109 | */ 110 | if($field.is(type[0])) { 111 | //如果不匹配 112 | if(!fieldPattern.test(fieldValue)){ 113 | if(fieldRequired){ 114 | status.pattern=false; 115 | }else{ 116 | if(fieldValue.length > 0){ 117 | status.pattern = false; 118 | } 119 | } 120 | } 121 | } 122 | 123 | //如果是data-conditional="name"函数验证,函数返回true或者是false 124 | if(fieldConditional !="undefined"){ 125 | if($.isFunction(fieldConditional)){ 126 | status.conditional=!!fieldConditional.call($field, fieldValue,options); 127 | }else{ 128 | if(options.conditional.hasOwnProperty(fieldConditional) && !options.conditional[fieldConditional].call($field,fieldValue,options)){ 129 | status.conditional=false; 130 | } 131 | } 132 | } 133 | 134 | 135 | //验证通过的信息所在对象 136 | 137 | log = errorTipFormat(fieldDescription.valid); 138 | if(!status.required) { 139 | log = errorTipFormat(fieldDescription.required); 140 | 141 | }else if(!status.pattern) { 142 | log = errorTipFormat(fieldDescription.pattern); 143 | 144 | 145 | } else if(!status.conditional) { 146 | log =errorTipFormat(fieldDescription.conditional); 147 | } 148 | 149 | var $describedShowElem=$('[id="' + fieldDescribedby +'"]'); 150 | //如果找打提示的容器,是第二种类型的验证 151 | if($describedShowElem.length > 0 && options.type==2){ 152 | //如果是change 或者是keyup 同时是第一次输入的时候就不要验证 153 | if((event.type=="keyup" || event.type=="change") && (!$describedShowElem.children().length || !$.trim($describedShowElem.text()))){ 154 | 155 | }else{ 156 | $describedShowElem.html(log || ''); 157 | fieldValidTypeHand($field,status,options) 158 | } 159 | } 160 | 161 | if(typeof(validation.each) == 'function') { 162 | validation.each.call($field, event, status, options); 163 | } 164 | 165 | typeof(options.eachField) === 'function' && options.eachField.call($field, event, status, options); 166 | 167 | if(status.required && status.pattern && status.conditional) { 168 | 169 | if(typeof(validation.valid) == 'function') {//二外拓展的 170 | validation.valid.call($field, event, status, options); 171 | } 172 | options.eachValidField.call($field, event, status, options); 173 | }else{//验证未通过 174 | if(!options.firstInvalid && options.firstInvalidFocus){ 175 | options.firstInvalid=true; 176 | $field.focus(); 177 | } 178 | if(options.type==1){ 179 | fieldTooltip.show(log) 180 | } 181 | if(typeof(validation.invalid) == 'function') { 182 | validation.invalid.call($field, event, status, options); 183 | } 184 | typeof(options.eachInvalidField) === 'function' && options.eachInvalidField.call($field, event, status, options); 185 | } 186 | 187 | /** 188 | * 如果是data-describedby="elemId"验证信息要显示的地方,类型3的验证: 189 | * 第一元素获取焦点,keyUp的时候要一直验证,如果正确那么错误信息就隐藏,如果不正确,那么错误 190 | * 提示信息要根据状态而改变,对于与验证通过,那么可以通过eachInvalid来让用户自定义,而无需要 191 | * 在插件中写它的操作方式 192 | */ 193 | return status; 194 | }; 195 | $.extend($,{ 196 | mvalidateExtend:function(options){ 197 | return $.extend(extend, options); 198 | } 199 | }); 200 | 201 | 202 | 203 | $.fn.mvalidate=function(options){ 204 | var defaults={ 205 | type:1, 206 | validateInSubmit:true, 207 | sendForm:true, 208 | onKeyup:false, 209 | onChange:true, 210 | firstInvalidFocus:true,//第一个未通过验证的表单是否获得交代呢 211 | conditional:{}, 212 | descriptions:{}, 213 | eachField : $.noop, 214 | eachValidField:$.noop, 215 | eachInvalidField : $.noop, 216 | valid:$.noop, 217 | invalid:$.noop, 218 | namespace:"mvalidate" 219 | }, 220 | opts=$.extend(true,defaults,options), 221 | flag, 222 | namespace=opts.namespace; 223 | 224 | opts.type=Number(opts.type); 225 | opts.firstInvalid=false; 226 | flag=opts.type==1 ? false : true; 227 | return this.mvalidateDestroy().each(function(event) { 228 | 229 | var $form=$(this), 230 | $fields;//存放当前表单下的所有元素; 231 | if(!$form.is("form")) return; 232 | opts.$form=$form; 233 | $form.data(namespace,{"options":opts}); 234 | $fields=$form.find(allTypes); 235 | 236 | // 237 | if(flag && opts.onKeyup){ 238 | $fields.filter(type[0]).each(function() { 239 | 240 | $(this).on("keyup."+namespace,function(event){ 241 | validateField.call(this,event,opts) 242 | }) 243 | }); 244 | } 245 | 246 | if(flag && opts.onChange){ 247 | $fields.each(function() { 248 | var $this=$(this); 249 | if($this.is(type[1]+ ',' + type[2])){ 250 | $(this).on('change.' + namespace, function(event) { 251 | validateField.call(this, event, opts); 252 | }) 253 | } 254 | }) 255 | } 256 | 257 | //如果需要验证的时候,在提交表单的时候对所有的字段进行验证 258 | if(opts.validateInSubmit){ 259 | $form.on("submit."+namespace,function(event){ 260 | var formValid = true; 261 | opts.firstInvalid=false; 262 | $fields.each(function() { 263 | var status=validateField.call(this,event,opts); 264 | if(!status.pattern || !status.conditional || !status.required) { 265 | formValid = false; 266 | } 267 | }); 268 | 269 | if(formValid){ 270 | if(!opts.sendForm){ 271 | event.preventDefault(); 272 | } 273 | if($.isFunction(opts.valid)){ 274 | opts.valid.call($form,event,opts); 275 | } 276 | //验证没有通过,禁用提交事件,以及绑定在这个elem上的其他事件 277 | }else{ 278 | event.preventDefault(); 279 | event.stopImmediatePropagation(); 280 | if($.isFunction(opts.invalid)) { 281 | opts.invalid.call($form,event,opts) 282 | } 283 | } 284 | 285 | }) 286 | } 287 | }) 288 | }; 289 | $.fn.mvalidateDestroy=function(){ 290 | var $form=$(this),$fields,namespace="mvalidate", 291 | dataValidate=$form.data(namespace); 292 | 293 | if(!dataValidate){ 294 | return $form; 295 | } 296 | if($form.is('form') && $.isPlainObject(dataValidate) && typeof(dataValidate.options.namespace) == 'string') { 297 | $fields = $form.removeData(name).find(allTypes); 298 | $fields.off('.' + dataValidate.options.namespace); 299 | } 300 | return $form; 301 | }; 302 | $.fn.mvalidate.errorTipFormat=function(text){ 303 | return '
'+text+'
'; 304 | } 305 | }) 306 | --------------------------------------------------------------------------------