前言
對於前端來說,沒有做過表單驗證是不可能的,但是,我們一般都是用的別人寫好的插件,反正都周末了,我們今天晚上就試着看看自己能不能寫一個出來試試呢?
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代碼:

<!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文件:

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代碼:

<!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>
結語
晃晃悠悠幾個小時就過去了,今天的任務沒能完成!!!!
寫到后面就沒有詳細寫下去了,因為我有幾個問題沒能解決,加之明天還要上班。。。。所以今天便不再堅持了。
明天晚上希望能解決自己的疑問,並整理下代碼,再詳加說明吧。