(转)工作了一个星期各位一定累了吧,那我们一起来表单验证一番吧!
原文地址:http://www.cnblogs.com/yexiaochai/archive/2013/06/01/3111699.html
前言
对于前端来说,没有做过表单验证是不可能的,但是,我们一般都是用的别人写好的插件,反正都周末了,我们今天晚上就试着看看自己能不能写一个出来试试呢?
PS:该产物纯粹实验产品,丑陋之处请多见谅!
验证的类型
常见的表单验证一般有以下几个:
① 非空验证
② 身份证验证
③ 数字验证(数字范围验证)
④ 邮件验证
⑤ 手机验证
⑥ QQ验证
⑦ 中文/英文用户名验证(可能含有AJAX类型验证)
⑧ 密码验证/重复密码验证
⑨ 单选框/下拉菜单/多选框验证
......
我那个去,简简单单一写怎么会有这么多东西呢!!!!看来今天晚上有点吃紧了,没事我们一步步来试试,确实不行也不会罚款,确实错了也没人责备,我们错得起。
表单提示框
友好的提示框是第一位的,来来,比如我们这里有个文本框,我们需要实现如下提示框:
我们一个怎么做呢?而且提示框种类比较多,我们便不强求了,但是以下两种也是很有可能出现的,我们是不是应该考虑呢?
若是我们的网页要求出现以上三种任意一种表现形式一完全合理的,所以我们还得都实现了!
但是实现前我们先干点其他事情,看看这段有意思的代码吧:
三角形图标
<div style=" width: 10px; height: 10px; border-width: 10px; border-style: solid; border-color: black Yellow Gray Green"></div>
这段代码很有意思,我们来看看他将形成的图形,以及去掉宽度与高度会形成的样子:
<div style="width: 10px; height: 10px; border-width: 10px; border-style: solid; border-color: black Yellow Gray Green; position: absolute;"> </div> <div style="border-width: 10px; border-style: solid; border-color: black Yellow Gray Green; position: absolute; top: 50px;">
这个图形很怪,我们看着他的几个边框居然形成了三角形!!!!那我们是不是可以省略图标了呢?
<div style="border-width: 10px; border-style: solid; border-color: transparent;
border-top-color: Black; position: absolute; top: 50px;">
<div style="border-width: 10px; border-style: solid; border-color: transparent; border-right-color: Black; position: absolute; top: 50px;">
<div style="border-width: 10px; border-style: solid; border-color: transparent; border-bottom-color: Black; position: absolute; top: 50px;">
<div style="border-width: 10px; border-style: solid; border-color: transparent; border-left-color: Black; position: absolute; top: 50px;">
以上这个东西各位应该都比较清楚的,而且看着提示图对他的使用也一定不言而喻,我这里还是赘述一下吧:
<div class="posTop" > <div class="triangle_icon"> <div class="before"></div> <div class="after"></div> </div>请输入数字 </div>
这就是图标的结构,以下是CSS样式:
.triangle_icon { position: absolute; } .triangle_icon div { border-style: solid; border-width: 6px; position: absolute; } /*上边提示*/ .posTop .triangle_icon { width: 12px; height: 12px; bottom: -12px; } .posTop .triangle_icon .after { bottom: 1px; } .posTop .triangle_icon .after { border-bottom-color: transparent; border-right-color: transparent; border-left-color: transparent; } .posTop .triangle_icon .before { border-bottom-color: transparent; border-right-color: transparent; border-left-color: transparent; }
为了根据外部ClassName而设置不同的展示方式,而且不同的状态拥有不同的样式,最后形成了这个CSS:
.validateTips { min-width: 100px; border-radius: 2px; padding: 5px 10px; z-index: 500; position: absolute; font-size: 12px; } .validateInit { background: #FFFFE0; border: 1px solid #F7CE39; } .validateError { background: orange; border: 1px solid red; } .validateSuc { background: #79D62D; border: 1px solid Green; } .triangle_icon { position: absolute; } .triangle_icon div { border-style: solid; border-width: 6px; position: absolute; } /*上边提示*/ .posTop .triangle_icon { width: 12px; height: 12px; bottom: -12px; } .posTop .triangle_icon .after { bottom: 1px; } .posTop .triangle_icon .after { border-bottom-color: transparent; border-right-color: transparent; border-left-color: transparent; } .posTop .triangle_icon .before { border-bottom-color: transparent; border-right-color: transparent; border-left-color: transparent; } /*右边提示*/ .posRight .triangle_icon { width: 12px; height: 12px; left: -12px; } .posRight .triangle_icon .after { left: 1px; } .posRight .triangle_icon .after { border-top-color: transparent; border-bottom-color: transparent; border-left-color: transparent; } .posRight .triangle_icon .before { border-top-color: transparent; border-bottom-color: transparent; border-left-color: transparent; } /*下边提示*/ .posBottom .triangle_icon { width: 12px; height: 12px; top: -12px; } .posBottom .triangle_icon .after { top: 1px; } .posBottom .triangle_icon .after { border-top-color: transparent; border-right-color: transparent; border-left-color: transparent; } .posBottom .triangle_icon .before { border-top-color: transparent; border-right-color: transparent; border-left-color: transparent; } /*初始化时候的皮肤*/ .validateInit .before { border-color: #F7CE39; } .validateInit .after { border-color: #FFFFE0; } /*失败时候的皮肤*/ .validateError .before { border-color: red; } .validateError .after { border-color: orange; } /*成功时候的皮肤*/ .validateSuc .before { border-color: Green; } .validateSuc .after { border-color: #79D62D; }
定位提示框
提示框样式有了,我们需要将它定位到特定的输入框之上,所以我规定了以下格式(实验产物,勿笑):
<div class="form"> <div> 身份证:<input type="text" id="idCard" class="formValidate" data-cfg="{ initMsg: '请输入身份证号码!' }" /> </div> <div> 数字:<input type="text" id="num" class="formValidate" data-cfg="{ initMsg: '请输入数字', msgPosition: 'top'}" /> </div> <div> 邮件:<input type="text" class="formValidate" data-cfg="{ initMsg: '请输入邮箱地址!'}" /> </div> <div> 手机:<input type="text" class="formValidate" data-cfg="{ msgPosition: 'bottom', initMsg: '请请输入手机号码!'}" /> </div> <div> QQ:<input type="text" class="formValidate" data-cfg="{ initMsg: '请请输入手机号码!'}" /> </div> <input type="button" value="提交" id="bt" /> </div>
我们这里对需要验证的文本框做了一个约束:
① 要求指定ID(不知道需要不,但是考虑到漂浮提示以后的控制还是加上吧)
② 必须指定class拥有formValidate
③ 必须指定自定义属性(json),将配置信息加上
于是我们加上js代码:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
![](https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif)
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title></title> <style type="text/css"> .form div { height: 30px; line-height: 30px; margin: 5px; } .validateTips { min-width: 100px; border-radius: 2px; padding: 5px 10px; z-index: 500; position: absolute; font-size: 12px; } .validateInit { background: #FFFFE0; border: 1px solid #F7CE39; } .validateError { background: orange; border: 1px solid red; } .validateSuc { background: #79D62D; border: 1px solid Green; } .triangle_icon { position: absolute; } .triangle_icon div { border-style: solid; border-width: 6px; position: absolute; } /*上边提示*/ .posTop .triangle_icon { width: 12px; height: 12px; bottom: -12px; } .posTop .triangle_icon .after { bottom: 1px; } .posTop .triangle_icon .after { border-bottom-color: transparent; border-right-color: transparent; border-left-color: transparent; } .posTop .triangle_icon .before { border-bottom-color: transparent; border-right-color: transparent; border-left-color: transparent; } /*右边提示*/ .posRight .triangle_icon { width: 12px; height: 12px; left: -12px; } .posRight .triangle_icon .after { left: 1px; } .posRight .triangle_icon .after { border-top-color: transparent; border-bottom-color: transparent; border-left-color: transparent; } .posRight .triangle_icon .before { border-top-color: transparent; border-bottom-color: transparent; border-left-color: transparent; } /*下边提示*/ .posBottom .triangle_icon { width: 12px; height: 12px; top: -12px; } .posBottom .triangle_icon .after { top: 1px; } .posBottom .triangle_icon .after { border-top-color: transparent; border-right-color: transparent; border-left-color: transparent; } .posBottom .triangle_icon .before { border-top-color: transparent; border-right-color: transparent; border-left-color: transparent; } /*初始化时候的皮肤*/ .validateInit .before { border-color: #F7CE39; } .validateInit .after { border-color: #FFFFE0; } /*失败时候的皮肤*/ .validateError .before { border-color: red; } .validateError .after { border-color: orange; } /*成功时候的皮肤*/ .validateSuc .before { border-color: Green; } .validateSuc .after { border-color: #79D62D; } </style> <script src="js/jquery-1.7.1.min.js" type="text/javascript"></script> <script src="js/yexiaochai_formValidator.js" type="text/javascript"></script> <script type="text/javascript"> $(document).ready(function () { $('.formValidate').each(function () { var el = $(this); var cfg = el.attr('data-cfg'); if (cfg && cfg.length > 0) { cfg = eval('(' + cfg + ')'); // cfg = JSON.parse(cfg); var initMsg = cfg.initMsg || '请填入信息'; var msgPosition = cfg.msgPosition || 'right'; var id = el.attr('id') || new Date().getTime(); var tips = $('<div class="validateTips validateInit" id="' + id + 'Tips"><div class="triangle_icon"><div class="before"></div><div class="after"></div></div>' + initMsg + '</div>'); var offset = el.offset(); var height = parseInt(el.outerHeight()); var width = parseInt(el.outerWidth()); var l = offset.left; var t = offset.top; if (msgPosition == 'bottom') { tips.addClass('posBottom'); t += height + 4; } else if (msgPosition == 'right') { tips.addClass('posRight'); l += width + 6; } else if (msgPosition == 'top') { tips.addClass('posTop'); t += height * (-1) - 8; } tips.css({ left: l, top: t }); $('body').append(tips); } }); //each }); </script> </head> <body> <div class="form"> <div> 身份证:<input type="text" id="idCard" class="formValidate" data-cfg="{ initMsg: '请输入身份证号码!' }" /> </div> <div> 数字:<input type="text" id="num" class="formValidate" data-cfg="{ initMsg: '请输入数字', msgPosition: 'top'}" /> </div> <div> 邮件:<input type="text" class="formValidate" data-cfg="{ initMsg: '请输入邮箱地址!'}" /> </div> <div> 手机:<input type="text" class="formValidate" data-cfg="{ msgPosition: 'bottom', initMsg: '请请输入手机号码!'}" /> </div> <div> QQ:<input type="text" class="formValidate" data-cfg="{ initMsg: '请请输入手机号码!'}" /> </div> <input type="button" value="提交" id="bt" /> </div> </body> </html>
于是我们密密麻麻的形成了这个页面,主要思路见代码,我这里简单说下:
1 根据class变量表单,获取每个元素
2 定位到每个元素,根据其配置信息,将提示框插入文本,并定位之。
至此,我们提示框像个就结束了,后面点的内容,我支支吾吾搞了好久都不太能推走了,我们接下来看看吧。
如何验证表单?
有了提示信息,另外一个问题马上就出现了
1 我应该如何验证表单呢?正则表达式?如果我写的不满足后续需求呢?
2 如何实现密码对比功能
3 如何实现选择框等功能
4 如何实现非空验证功能
5 如何取消验证
6 取消验证后如何加上某项验证
......
一系列问题抛了出来,我就边写边思考,最后搞出来都面目全非了,形成了这样的代码:
js文件:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
![](https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif)
1 (function ($) { 2 var FormValidator = function () { 3 this.regexEnum = { 4 idCard: /^[1-9]([0-9]{14}|[0-9]{16})([0-9]|X)$/, 5 num: /^\-?([1-9]\d*)$/, //数字 6 email: /^([0-9A-Za-z\-_\.]+)@([0-9a-z]+\.[a-z]{2,3}(\.[a-z]{2})?)$/, 7 phone: /^1[3|4|5|8]\d{9}$/ 8 }; 9 this.validatorArr = {}; 10 }; 11 12 FormValidator.prototype.init = function () { 13 var scope = this; 14 $('.formValidate').each(function () { 15 var el = $(this); 16 scope.initItem(el); 17 }); //each 18 }; 19 20 FormValidator.prototype.initItem = function (el) { 21 var scope = this; 22 var cfg = el.attr('data-cfg'); 23 24 if (cfg && cfg.length > 0) { 25 cfg = eval('(' + cfg + ')'); 26 // cfg = JSON.parse(cfg); 27 var check = cfg.check || true, 28 id = el.attr('id') || new Date().getTime(), 29 initMsg = cfg.initMsg || '请填入信息', 30 sucMsg = cfg.sucMsg || '格式正确', 31 errorMsg = cfg.errorMsg || '请注意格式', 32 type = cfg.type || '', 33 requred = cfg.requred || false, 34 msgPosition = cfg.msgPosition || 'right'; 35 36 cfg.id = id; 37 cfg.initMsg = initMsg; 38 cfg.sucMsg = sucMsg; 39 cfg.errorMsg = errorMsg; 40 cfg.type = type; 41 cfg.msgPosition = msgPosition; 42 cfg.requred = requred; 43 cfg.requredMsg = cfg.requredMsg || '该项必填'; 44 45 if (check) { 46 var tips = $('<div class="validateTips validateInit" id="' + id + 'Tips"><div class="triangle_icon"><div class="before"></div><div class="after"></div></div>' + initMsg + '</div>'); 47 // var tips = $('<div class="validateTips validateInit" id="' + id + 'Tips">' + initMsg + '</div>'); 48 var offset = el.offset(); 49 var height = parseInt(el.outerHeight()); 50 var width = parseInt(el.outerWidth()); 51 var l = offset.left; 52 var t = offset.top; 53 if (msgPosition == 'bottom') { 54 tips.addClass('posBottom'); 55 t += height + 4; 56 } else if (msgPosition == 'right') { 57 tips.addClass('posRight'); 58 l += width + 6; 59 } else if (msgPosition == 'top') { 60 tips.addClass('posTop'); 61 t += height * ( -1) - 8; 62 } 63 64 tips.css({ left: l, top: t }); 65 $('body').append(tips); 66 cfg.el = el; 67 cfg.tipEl = tips; 68 69 el.focus(function () { 70 scope.funcValidate(el, cfg); 71 }); 72 el.blur(function () { 73 scope.funcValidate(el, cfg); 74 }); 75 el.keyup(function () { 76 scope.funcValidate(el, cfg); 77 }); 78 el.keydown(function () { 79 scope.funcValidate(el, cfg); 80 }); 81 cfg.validate = function () { 82 scope.funcValidate(el, cfg); 83 }; 84 scope.validatorArr[id] = cfg; //生成相关验证对象 85 } 86 87 } else { 88 console.log('请输入完整验证信息!否则控件会产生错误!'); 89 } 90 }; 91 92 FormValidator.prototype.funcValidate = function (el, cfg) { 93 var id = cfg.id; 94 95 //取消事件不执行下面逻辑 96 if (!this.validatorArr[id]) 97 return false; 98 99 var type = cfg.type; 100 var requred = cfg.requred; 101 if (!type && !this.regexEnum[type]) { 102 return false; 103 } 104 var isPass = 0; //0初始状态,1成功,-1错误 105 var msg = ''; 106 var r = this.regexEnum[type] ? this.regexEnum[type] : type; 107 108 if (requred && el.val() == '') { 109 isPass = -1; 110 msg = cfg.requredMsg; 111 } else { 112 if (el.val() == '') { 113 isPass = 0; 114 msg = cfg.initMsg; 115 } else { 116 if (r.test(el.val())) { 117 isPass = 1; 118 msg = cfg.sucMsg; 119 } else { 120 isPass = -1; 121 msg = cfg.errorMsg; 122 } 123 } 124 } 125 if (isPass == 0) { 126 this.validatorArr[id]['tipEl'].removeClass('validateError'); 127 this.validatorArr[id]['tipEl'].removeClass('validateSuc'); 128 this.validatorArr[id]['tipEl'].addClass('validateInit'); 129 this.validatorArr[id]['tipEl'].html('<div class="triangle_icon"><div class="before"></div><div class="after"></div></div>' + msg); 130 } else if (isPass == 1) { 131 this.validatorArr[id]['state'] = 'success'; 132 this.validatorArr[id]['tipEl'].removeClass('validateError'); 133 this.validatorArr[id]['tipEl'].removeClass('validateInit'); 134 this.validatorArr[id]['tipEl'].addClass('validateSuc'); 135 this.validatorArr[id]['tipEl'].html('<div class="triangle_icon"><div class="before"></div><div class="after"></div></div>' + msg); 136 } else if (isPass == -1) { 137 this.validatorArr[id]['state'] = 'error'; 138 this.validatorArr[id]['tipEl'].removeClass('validateSuc'); 139 this.validatorArr[id]['tipEl'].removeClass('validateInit'); 140 this.validatorArr[id]['tipEl'].addClass('validateError'); 141 this.validatorArr[id]['tipEl'].html('<div class="triangle_icon"><div class="before"></div><div class="after"></div></div>' + msg); 142 } 143 }; 144 145 FormValidator.prototype.validatorAll = function () { 146 for (var k in this.validatorArr) { 147 var v = this.validatorArr[k]; 148 v.validate(); 149 } 150 }; 151 152 FormValidator.prototype.removeValidator = function (id) { 153 if (id && this.validatorArr[id]) { 154 // this.validatorArr[id].tipEl 155 this.validatorArr[id].tipEl.remove(); //删除提示信息 156 delete this.validatorArr[id]; //删除该验证项目 157 // this.validatorArr[id].el.unbind();//移除所有事件,但是考虑标签可能会有其他事件,此处暂时不予处理 158 var s = ''; 159 } 160 }; 161 162 FormValidator.prototype.addValidator = function (id) { 163 var el = $('#' + id); 164 this.initItem(el); 165 }; 166 167 FormValidator.prototype.validatorState = function () { 168 for (var k in this.validatorArr) { 169 var v = this.validatorArr[k]; 170 if (v.state == 'error') { 171 return false; 172 } 173 } 174 return true; 175 }; 176 window.FormValidator = FormValidator; 177 })(jQuery);
html代码:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
![](https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif)
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title></title> <style type="text/css"> .form div { height: 30px; line-height: 30px; margin: 5px; } .validateTips { min-width: 100px; border-radius: 2px; padding: 5px 10px; z-index: 500; position: absolute; font-size: 12px; } .validateInit { background: #FFFFE0; border: 1px solid #F7CE39; } .validateError { background: orange; border: 1px solid red; } .validateSuc { background: #79D62D; border: 1px solid Green; } .triangle_icon { position: absolute; } .triangle_icon div { border-style: solid; border-width: 6px; position: absolute; } /*上边提示*/ .posTop .triangle_icon { width: 12px; height: 12px; bottom: -12px; } .posTop .triangle_icon .after { bottom: 1px; } .posTop .triangle_icon .after { border-bottom-color: transparent; border-right-color: transparent; border-left-color: transparent; } .posTop .triangle_icon .before { border-bottom-color: transparent; border-right-color: transparent; border-left-color: transparent; } /*右边提示*/ .posRight .triangle_icon { width: 12px; height: 12px; left: -12px; } .posRight .triangle_icon .after { left: 1px; } .posRight .triangle_icon .after { border-top-color: transparent; border-bottom-color: transparent; border-left-color: transparent; } .posRight .triangle_icon .before { border-top-color: transparent; border-bottom-color: transparent; border-left-color: transparent; } /*下边提示*/ .posBottom .triangle_icon { width: 12px; height: 12px; top: -12px; } .posBottom .triangle_icon .after { top: 1px; } .posBottom .triangle_icon .after { border-top-color: transparent; border-right-color: transparent; border-left-color: transparent; } .posBottom .triangle_icon .before { border-top-color: transparent; border-right-color: transparent; border-left-color: transparent; } /*初始化时候的皮肤*/ .validateInit .before { border-color: #F7CE39; } .validateInit .after { border-color: #FFFFE0; } /*失败时候的皮肤*/ .validateError .before { border-color: red; } .validateError .after { border-color: orange; } /*成功时候的皮肤*/ .validateSuc .before { border-color: Green; } .validateSuc .after { border-color: #79D62D; } </style> <script src="js/jquery-1.7.1.min.js" type="text/javascript"></script> <script src="js/yexiaochai_formValidator.js" type="text/javascript"></script> <script type="text/javascript"> $(document).ready(function () { var f = new FormValidator(); f.init(); f.validatorAll(); var bt = $('#bt'); var add = $('#add'); var remove = $('#remove'); var name = $('#name'); bt.click(function () { var end = f.validatorState(); var s = ''; }); add.click(function () { f.addValidator(name.val()); var s = ''; }); remove.click(function () { f.removeValidator(name.val()); var s = ''; }); }); </script> </head> <body> <input type="text" id="name" /> <input type="button" value="取消验证" id="remove" /> <input type="button" value="添加验证" id="add" /> <div class="form"> <div> 身份证:<input type="text" id="idCard" class="formValidate" data-cfg="{ check: 'true', type: 'idCard', msgPosition: 'right', initMsg: '请输入身份证号码!', requred: true, sucMsg: '正确', errorMsg: '格式错误'}" /> </div> <div> 数字:<input type="text" id="num" class="formValidate" data-cfg="{ type: 'num', initMsg: '请输入数字', msgPosition: 'top'}" /> </div> <div> 邮件:<input type="text" class="formValidate" data-cfg="{ type: 'email', initMsg: '请输入邮箱地址!'}" /> </div> <div> 手机:<input type="text" class="formValidate" data-cfg="{ type: 'phone', initMsg: '请请输入手机号码!'}" /> </div> <div> QQ:<input type="text" class="formValidate" data-cfg="{ type: /^[1-9]*[1-9][0-9]*$/, initMsg: '请请输入手机号码!'}" /> </div> <div> 用户名:<input type="text" /> </div> <div> 密码:<input type="text" /> </div> <div> 重复密码:<input type="text" /> </div> <div> 性别: <label> <input type="radio" name="Gender" value="0" /> 男</label> <label> <input type="radio" name="Gender" value="1" /> 女</label> </div> <div> 爱好: <label> <input type="checkbox" name="aihao" value="0" /> 爱好1</label> <label> <input type="checkbox" name="aihao" value="1" /> 爱好2</label> <label> <input type="checkbox" name="aihao" value="0" /> 爱好3</label> <label> <input type="checkbox" name="aihao" value="1" /> 爱好4</label> </div> <input type="button" value="提交" id="bt" /> </div> </body> </html>
结语
晃晃悠悠几个小时就过去了,今天的任务没能完成!!!!
写到后面就没有详细写下去了,因为我有几个问题没能解决,加之明天还要上班。。。。所以今天便不再坚持了。
明天晚上希望能解决自己的疑问,并整理下代码,再详加说明吧。