前言
接着昨天的寫:工作了一個星期各位一定累了吧,那我們一起來表單驗證一番吧!
因為昨天寫到后面確實寫不動了,就停下了,今天我們繼續吧,看看能不能解決昨天提出的幾個問題,由於今天看了下別人寫的插件,在里面找到了一些很不錯的點子,這里也應用起來了,慢慢改造我們的程序吧。
現狀
經過今天的奮戰,我們的界面變成了這個樣子啦:
代碼變成了這個樣子:
js代碼

/// <reference path="jquery-1.7.1.min.js" /> (function ($) { var FormValidator = function () { this.regexEnum = { idCard: /^[1-9]([0-9]{14}|[0-9]{16})([0-9]|X)$/, num: /^\-?([1-9]\d*)$/, //數字 email: /^([0-9A-Za-z\-_\.]+)@([0-9a-z]+\.[a-z]{2,3}(\.[a-z]{2})?)$/, phone: /^1[3|4|5|8]\d{9}$/, chinese: /^[\u0391-\uFFE5]{2,6}$/, //2-6位中文 password: /^[a-zA-Z0-9_]{8,32}$/ //6-32位密碼驗證 }; this.validatorArr = {}; }; FormValidator.prototype.requred = function (el) { // if (el.val() == '') { // return false; // } return true; } FormValidator.prototype.init = function () { var scope = this; $('.formValidate').each(function () { var el = $(this); scope.initItem(el); }); //each }; FormValidator.prototype.initItem = function (el) { if (typeof el == 'string') el = $('#' + el); var scope = this; var cfg = el.attr('data-cfg'); if (cfg && cfg.length > 0) { cfg = eval('(' + cfg + ')'); // cfg = JSON.parse(cfg); var check = cfg.check || true, id = el.attr('id') || new Date().getTime(), initMsg = cfg.initMsg || '請填入信息', sucMsg = cfg.sucMsg || '格式正確', errorMsg = cfg.errorMsg || '請注意格式', requred = cfg.requred || false, msgPosition = cfg.msgPosition || 'right'; cfg.id = id; cfg.check = check; cfg.initMsg = initMsg; cfg.sucMsg = sucMsg; cfg.errorMsg = errorMsg; cfg.msgPosition = msgPosition; cfg.requred = requred; 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 tips = $('<div class="validateTips validateInit" id="' + id + 'Tips">' + 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); cfg.el = el; cfg.tipEl = tips; //該表單的驗證 cfg.validate = function () { scope.funcValidate(el, cfg); }; //會觸發驗證的事件(取消驗證后,該事件取消的話害怕引起事件丟失) el.change(function () { scope.funcValidate(el, cfg); }); el.focus(function () { scope.funcValidate(el, cfg); }); el.blur(function () { scope.funcValidate(el, cfg); }); el.keyup(function () { scope.funcValidate(el, cfg); }); el.keydown(function () { scope.funcValidate(el, cfg); }); scope.validatorArr[id] = cfg; //生成相關驗證對象 } else { console.log('請輸入完整驗證信息!否則控件會產生錯誤!'); } }; FormValidator.prototype.funcValidate = function (el, cfg) { var id = cfg.id; var check = cfg.check; //判斷是否開啟驗證 //取消事件不執行下面邏輯 if (!this.validatorArr[id]) return false; //若是沒有開啟驗證便忽略之 if (!check) { this.validatorArr[id]['state'] = 'ignore'; return false; } var type = cfg.type; var regexObj = cfg.regexObj; //正則相關 var rangeObj = cfg.rangeObj; //范圍驗證 var compareObj = cfg.compareObj; //范圍驗證 var msg = ''; var isPass = 1; //1成功,-1錯誤 //首先進行非空驗證 if (cfg.requred) { if (el.val() == '') { isPass = -1; msg = '該項必填'; } } //type優先 if (isPass == 1 && el.val().length > 0 && typeof type == 'string') { var typeArr = type.split('|'); //可能包含驗證組 var errorArr = cfg.errorMsg.split('|'); //各個組錯誤時候對應的信息 for (var i = 0, len = typeArr.length; i < len; i++) { var r = this.regexEnum[typeArr[i]]; //測試通過 if (r.test(el.val())) { msg = cfg.sucMsg; } else { isPass = -1; msg = errorArr[i] ? errorArr[i] : cfg.errorMsg; break; //一旦有錯誤的地方便中斷 } } } //當第一步驗證通過便執行自身正則驗證 if (isPass == 1 && el.val().length > 0 && regexObj) { //當未指定type時候,便執行頁面中的正則表達式對象 var r = regexObj; if (r.test(el.val())) { msg = cfg.sucMsg; } else { isPass = -1; msg = cfg.errorMsg; } } //當第二步驗證通過便執行范圍驗證 if (isPass == 1 && el.val().length > 0 && rangeObj) { //日期驗證暫時忽略 var rangeArr = rangeObj.split('|'); if (rangeArr.length == 3) { var _v = el.val(); var _p1 = rangeArr[1]; var _p2 = rangeArr[2]; if (rangeArr[0] == 'num') { _v = parseInt(el.val()); _p1 = parseInt(rangeArr[1]); _p2 = parseInt(rangeArr[2]); } if (_v > _p1 && _v < _p2) { msg = cfg.sucMsg; } else { isPass = -1; msg = '請填入' + rangeArr[0] + '到' + rangeArr[1] + '直接的數字'; } } else { console.log('范圍參數錯誤'); } } //執行對比運算 if (isPass == 1 && el.val().length > 0 && compareObj) { var compareArr = compareObj.split('|'); if (compareArr.length == 3) { var _type = compareArr[0] var _id = compareArr[1]; var _flag = compareArr[2]; var _v = el.val(); var _cv = $('#' + _id).val(); if (_type == 'num') { _v = parseInt(_v); _cv = parseInt(_cv); } if (_flag == '<') { if (_v < _cv) { msg = cfg.sucMsg; } else { isPass = -1; msg = '該值過大'; } } if (_flag == '>') { if (_v > _cv) { msg = cfg.sucMsg; } else { isPass = -1; msg = '該值過小'; } } if (_flag == '=') { if (_v == _cv) { msg = cfg.sucMsg; } else { isPass = -1; msg = '兩次數據不一致'; } } } else { console.log('范圍參數錯誤'); } } if (msg == '') isPass = 0; if (isPass == 0) { this.validatorArr[id]['state'] = 'init'; this.validatorArr[id]['tipEl'].removeClass('validateError'); this.validatorArr[id]['tipEl'].removeClass('validateSuc'); this.validatorArr[id]['tipEl'].addClass('validateInit'); this.validatorArr[id]['tipEl'].html('<div class="triangle_icon"><div class="before"></div><div class="after"></div></div>' + cfg.initMsg); } else if (isPass == 1) { this.validatorArr[id]['state'] = 'success'; this.validatorArr[id]['tipEl'].removeClass('validateError'); this.validatorArr[id]['tipEl'].removeClass('validateInit'); this.validatorArr[id]['tipEl'].addClass('validateSuc'); this.validatorArr[id]['tipEl'].html('<div class="triangle_icon"><div class="before"></div><div class="after"></div></div>' + msg); } else if (isPass == -1) { this.validatorArr[id]['state'] = 'error'; this.validatorArr[id]['tipEl'].removeClass('validateSuc'); this.validatorArr[id]['tipEl'].removeClass('validateInit'); this.validatorArr[id]['tipEl'].addClass('validateError'); this.validatorArr[id]['tipEl'].html('<div class="triangle_icon"><div class="before"></div><div class="after"></div></div>' + msg); } }; FormValidator.prototype.validatorAll = function () { for (var k in this.validatorArr) { var v = this.validatorArr[k]; v.validate(); } }; FormValidator.prototype.removeValidator = function (id) { if (id && this.validatorArr[id]) { this.validatorArr[id].tipEl.remove(); //刪除提示信息 this.validatorArr[id]['check'] = false; //將其驗證狀態置為false var s = ''; } }; FormValidator.prototype.addValidator = function (id) { var el = $('#' + id); this.initItem(el); }; FormValidator.prototype.validatorState = function () { for (var k in this.validatorArr) { var v = this.validatorArr[k]; if (v.state == 'error') { return false; } } return true; }; window.FormValidator = FormValidator; })(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; } /*表單相關樣式,和驗證無關,可刪除*/ .form { width: 820px; margin: 0 auto; } .form ul { list-style-type: none; padding-left: 0; } .form li > label { display: inline-block; min-width: 200px; padding-right: 14px; text-align: right; vertical-align: -2px; } .form ul .text { display: inline-block; line-height: 40px; margin-left: 10px; } /*表單相關樣式,和驗證無關,可刪除*/ </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'); var single = $('#single'); bt.click(function () { f.validatorAll(); var end = f.validatorState(); var s = ''; }); single.click(function () { f.initItem(name.val()); var s = ''; }); add.click(function () { f.addValidator(name.val()); var s = ''; }); remove.click(function () { f.removeValidator(name.val()); var s = ''; }); }); </script> </head> <body> <div class="form"> <input type="text" id="name" /> <input type="button" value="取消驗證" id="remove" /> <input type="button" value="添加驗證" id="add" /> <input type="button" value="單項驗證" id="single" /> <ul> <li> <label> 身份證:</label> <div class="text"> <input type="text" id="idCard" class="formValidate" data-cfg="{ requred: true, type: 'idCard', msgPosition: 'right', initMsg: '請輸入身份證號碼!', sucMsg: '正確', errorMsg: '該項必填|格式錯誤'}" /> </div> </li> <li> <label> 數字: </label> <div class="text"> <input type="text" id="num" class="formValidate" data-cfg="{ type: 'num'}" /> </div> </li> <li> <label> 郵件: </label> <div class="text"> <input type="text" class="formValidate" data-cfg="{ type: 'email', initMsg: '請輸入郵箱地址!'}" /> </div> </li> <li> <label> 手機: </label> <div class="text"> <input type="text" class="formValidate" data-cfg="{ type: 'phone', initMsg: '請請輸入手機號碼!'}" /> </div> </li> <li> <label> QQ: </label> <div class="text"> <input type="text" class="formValidate" data-cfg="{ regexObj: /^[1-9]*[1-9][0-9]*$/, initMsg: '請請輸入手機號碼!'}" /> </div> </li> <li> <label> 年齡要求(18-25): </label> <div class="text"> <input type="text" class="formValidate" data-cfg="{ rangeObj: 'num|18|25', initMsg: '請輸入您的年齡'}" /> </div> </li> <li> <label> 用戶名: </label> <div class="text"> <input type="text" class="formValidate" />(ajax類型測試) </div> </li> <li> <label> 密碼: </label> <div class="text"> <input type="text" id="pwd" class="formValidate" data-cfg="{ requred: true, type: 'password', msgPosition: 'right', initMsg: '請輸入密碼!', sucMsg: '正確', errorMsg: '格式錯誤'}" /> </div> </li> <li> <label> 重復密碼: </label> <div class="text"> <input type="text" id="rePwd" class="formValidate" data-cfg="{ compareObj: 'str|pwd|=', requred: true}" />(驗證對比時,應該考慮日期,字符串,數字) </div> </li> <li> <label> 工作年限/薪水范圍: </label> <div class="text"> <input type="text" id="d_start" class="formValidate" data-cfg="{ type: 'num', msgPosition: 'bottom' }" />- <input type="text" id="d_end" class="formValidate" data-cfg="{ compareObj: 'num|d_start|>', type: 'num', msgPosition: 'bottom' }" /> </div> </li> <li> <br /> <br /> <label> 學歷: </label> <div class="text"> <select id="sec" class="formValidate" data-cfg="{ requred: true, initMsg: '請選擇學歷!', sucMsg: '正確', errorMsg: '必須選擇學歷' }"> <option value="" selected="selected">請選擇</option> <option value="1">專科</option> <option value="2">本科</option> <option value="3">碩士</option> </select> </div> </li> </ul> <input type="button" value="提交" id="bt" /> </div> </body> </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; } /*表單相關樣式,和驗證無關,可刪除*/ .form { width: 820px; margin: 0 auto; } .form ul { list-style-type: none; padding-left: 0; } .form li > label { display: inline-block; min-width: 200px; padding-right: 14px; text-align: right; vertical-align: -2px; } .form ul .text { display: inline-block; line-height: 40px; margin-left: 10px; } /*表單相關樣式,和驗證無關,可刪除*/ </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'); var single = $('#single'); bt.click(function () { f.validatorAll(); var end = f.validatorState(); var s = ''; }); single.click(function () { f.initItem(name.val()); var s = ''; }); add.click(function () { f.addValidator(name.val()); var s = ''; }); remove.click(function () { f.removeValidator(name.val()); var s = ''; }); }); </script> </head> <body> <div class="form"> <input type="text" id="name" /> <input type="button" value="取消驗證" id="remove" /> <input type="button" value="添加驗證" id="add" /> <input type="button" value="單項驗證" id="single" /> <ul> <li> <label> 用戶名: </label> <div class="text"> <input type="text" class="formValidate" data-cfg="{ ajaxObj: 'ajax.ashx|name', requred: true, type: 'chinese', initMsg: '請輸入中文名!', sucMsg: '名字正確', errorMsg: '格式錯誤' }" />(ajax類型測試) </div> </li> </ul> <input type="button" value="提交" id="bt" /> </div> </body> </html>
我們就看着一個文本框的驗證,這里我們來捋一捋這個js代碼先:
1 定義構造函數
1 var FormValidator = function () { 2 this.regexEnum = { 3 idCard: /^[1-9]([0-9]{14}|[0-9]{16})([0-9]|X)$/, 4 num: /^\-?([1-9]\d*)$/, //數字 5 email: /^([0-9A-Za-z\-_\.]+)@([0-9a-z]+\.[a-z]{2,3}(\.[a-z]{2})?)$/, 6 phone: /^1[3|4|5|8]\d{9}$/, 7 chinese: /^[\u0391-\uFFE5]{2,6}$/, //2-6位中文 8 password: /^[a-zA-Z0-9_]{8,32}$/ //6-32位密碼驗證 9 }; 10 this.validatorArr = {}; 11 };
這里定義了一個構造函數,我們這里每次驗證時候都必須初始化一次(new一次),其中第十行是保存其所有項目的驗證對象(這里取名為數組其實是個錯誤)。
我們來看看這個regexEnum對象包含了我們常用的正則驗證,若是不能滿足條件可以再加,於是這里就有一個問題:
我們的regexEnum其實是可以共用的,這里寫到這里其實不合適,我們應該將其提出來,但我這里先暫時不管他了。
2 初始化各個表單項
1 FormValidator.prototype.init = function () { 2 var scope = this; 3 $('.formValidate').each(function () { 4 var el = $(this); 5 scope.initItem(el); 6 }); //each 7 };
這個方法用於遍歷具有“formValidate”的class的標簽,並單個對其初始化:
1 FormValidator.prototype.initItem = function (el) { 2 if (typeof el == 'string') el = $('#' + el); 3 var scope = this; 4 var cfg = el.attr('data-cfg'); 5 6 if (cfg && cfg.length > 0) { 7 cfg = eval('(' + cfg + ')'); 8 // cfg = JSON.parse(cfg); 9 var check = cfg.check || true, 10 id = el.attr('id') || new Date().getTime(), 11 initMsg = cfg.initMsg || '請填入信息', 12 sucMsg = cfg.sucMsg || '格式正確', 13 errorMsg = cfg.errorMsg || '請注意格式', 14 requred = cfg.requred || false, 15 msgPosition = cfg.msgPosition || 'right'; 16 cfg.id = id; 17 cfg.check = check; 18 cfg.initMsg = initMsg; 19 cfg.sucMsg = sucMsg; 20 cfg.errorMsg = errorMsg; 21 cfg.msgPosition = msgPosition; 22 cfg.requred = requred; 23 24 var tips = $('<div class="validateTips validateInit" id="' + id + 'Tips"><div class="triangle_icon"><div class="before"> </div><div class="after"></div></div>' + initMsg + '</div>'); 25 // var tips = $('<div class="validateTips validateInit" id="' + id + 'Tips">' + initMsg + '</div>'); 26 var offset = el.offset(); 27 var height = parseInt(el.outerHeight()); 28 var width = parseInt(el.outerWidth()); 29 var l = offset.left; 30 var t = offset.top; 31 32 if (msgPosition == 'bottom') { 33 tips.addClass('posBottom'); 34 t += height + 4; 35 } else if (msgPosition == 'right') { 36 tips.addClass('posRight'); 37 l += width + 6; 38 } else if (msgPosition == 'top') { 39 tips.addClass('posTop'); 40 t += height * (-1) - 8; 41 } 42 tips.css({ left: l, top: t }); 43 $('body').append(tips); 44 45 cfg.el = el; 46 cfg.tipEl = tips; 47 //該表單的驗證 48 cfg.validate = function () { 49 scope.funcValidate(el, cfg); 50 }; 51 52 //會觸發驗證的事件(取消驗證后,該事件取消的話害怕引起事件丟失) 53 el.change(function () { 54 scope.funcValidate(el, cfg); 55 }); 56 el.focus(function () { 57 scope.funcValidate(el, cfg); 58 }); 59 el.blur(function () { 60 scope.funcValidate(el, cfg); 61 }); 62 el.keyup(function () { 63 scope.funcValidate(el, cfg); 64 }); 65 el.keydown(function () { 66 scope.funcValidate(el, cfg); 67 }); 68 69 scope.validatorArr[id] = cfg; //生成相關驗證對象 70 71 } else { 72 console.log('請輸入完整驗證信息!否則控件會產生錯誤!'); 73 } 74 };
這個方法是用於初始化單個標簽的,他的代碼很長,但是卻很簡單,主要干了這么幾件事情:
① 生成提示框,並定位到文本框附近
② 為文本框綁定各種事件,用於驗證時候使用
③ 初始化validatorArr對象,將單項裝入
這個方法就干了這些事情,但是他是有一定問題的,我們這里首先看看其將觸發哪些事件:
1 //會觸發驗證的事件(取消驗證后,該事件取消的話害怕引起事件丟失) 2 el.change(function () { 3 scope.funcValidate(el, cfg); 4 }); 5 el.focus(function () { 6 scope.funcValidate(el, cfg); 7 }); 8 el.blur(function () { 9 scope.funcValidate(el, cfg); 10 }); 11 el.keyup(function () { 12 scope.funcValidate(el, cfg); 13 }); 14 el.keydown(function () { 15 scope.funcValidate(el, cfg); 16 });
這段代碼本身沒有什么問題,用於一般的驗證還是可以接受的,但是若是用於ajax的話,不幸的事實告訴我他請求發的太多了。。。。
但是,我們這里又必須保證他的及時性,感覺還不能延遲請求呢,所以我這里去掉了兩個事件:
el.blur(function () { scope.funcValidate(el, cfg); }); el.keydown(function () { scope.funcValidate(el, cfg); });
所以原來就保留了三個事件,應該也夠了吧。
然后這里調用了一個funcValidate(el, cfg)方法,用於單個驗證,並改變提示信息,但是我們這里又有一個問題:
PS:細細讀起來怎么這么多問題呢?汗。。。
這里,傳的參數el是多余的,因為cfg里面就包含了這個東西,所以我們把它去掉。於是我們接着往下走:

FormValidator.prototype.funcValidate = function (cfg) { var id = cfg.id; var el = cfg.el; var check = cfg.check; //判斷是否開啟驗證 var that = this; //取消事件不執行下面邏輯 if (!this.validatorArr[id]) return false; //若是沒有開啟驗證便忽略之 if (!check) { this.validatorArr[id]['state'] = 'ignore'; return false; } var type = cfg.type; var regexObj = cfg.regexObj; //正則相關 var rangeObj = cfg.rangeObj; //范圍驗證 var compareObj = cfg.compareObj; //范圍驗證 var ajaxObj = cfg.ajaxObj; //ajax驗證 var msg = ''; var isPass = 1; //1成功,-1錯誤 //首先進行非空驗證 if (cfg.requred) { if (el.val() == '') { isPass = -1; msg = '該項必填'; } } //type優先 if (isPass == 1 && el.val().length > 0 && typeof type == 'string') { var typeArr = type.split('|'); //可能包含驗證組 var errorArr = cfg.errorMsg.split('|'); //各個組錯誤時候對應的信息 for (var i = 0, len = typeArr.length; i < len; i++) { var r = this.regexEnum[typeArr[i]]; //測試通過 if (r.test(el.val())) { msg = cfg.sucMsg; } else { isPass = -1; msg = errorArr[i] ? errorArr[i] : cfg.errorMsg; break; //一旦有錯誤的地方便中斷 } } } //當第一步驗證通過便執行自身正則驗證 if (isPass == 1 && el.val().length > 0 && regexObj) { //當未指定type時候,便執行頁面中的正則表達式對象 var r = regexObj; if (r.test(el.val())) { msg = cfg.sucMsg; } else { isPass = -1; msg = cfg.errorMsg; } } //當第二步驗證通過便執行范圍驗證 if (isPass == 1 && el.val().length > 0 && rangeObj) { //日期驗證暫時忽略 var rangeArr = rangeObj.split('|'); if (rangeArr.length == 3) { var _v = el.val(); var _p1 = rangeArr[1]; var _p2 = rangeArr[2]; if (rangeArr[0] == 'num') { _v = parseInt(el.val()); _p1 = parseInt(rangeArr[1]); _p2 = parseInt(rangeArr[2]); } if (_v > _p1 && _v < _p2) { msg = cfg.sucMsg; } else { isPass = -1; msg = '請填入' + rangeArr[0] + '到' + rangeArr[1] + '直接的數字'; } } else { console.log('范圍參數錯誤'); } } //執行對比運算 if (isPass == 1 && el.val().length > 0 && compareObj) { var compareArr = compareObj.split('|'); if (compareArr.length == 3) { var _type = compareArr[0] var _id = compareArr[1]; var _flag = compareArr[2]; var _v = el.val(); var _cv = $('#' + _id).val(); if (_type == 'num') { _v = parseInt(_v); _cv = parseInt(_cv); } if (_flag == '<') { if (_v < _cv) { msg = cfg.sucMsg; } else { isPass = -1; msg = '該值過大'; } } if (_flag == '>') { if (_v > _cv) { msg = cfg.sucMsg; } else { isPass = -1; msg = '該值過小'; } } if (_flag == '=') { if (_v == _cv) { msg = cfg.sucMsg; } else { isPass = -1; msg = '兩次數據不一致'; } } } else { console.log('范圍參數錯誤'); } } //ajax驗證 if (isPass == 1 && el.val().length > 0 && ajaxObj) { var ajaxArr = ajaxObj.split('|'); if (ajaxArr.length == 2) { var _url = ajaxArr[0]; var _param = {}; _param[ajaxArr[1]] = el.val(); $.get(_url, _param, function (data) { if (typeof data == 'string') data = eval('(' + data + ')'); if (data.retcode == '0') { msg = cfg.sucMsg; } else { isPass = -1; msg = data.msg; } setResult(that, isPass); }); return false; //在此中斷后續操作 } } setResult(this, isPass); function setResult(scope, isPass) { if (msg == '') isPass = 0; if (isPass == 0) { scope.validatorArr[id]['state'] = 'init'; scope.validatorArr[id]['tipEl'].removeClass('validateError'); scope.validatorArr[id]['tipEl'].removeClass('validateSuc'); scope.validatorArr[id]['tipEl'].addClass('validateInit'); scope.validatorArr[id]['tipEl'].html('<div class="triangle_icon"><div class="before"></div> <div class="after"></div></div>' + cfg.initMsg); } else if (isPass == 1) { scope.validatorArr[id]['state'] = 'success'; scope.validatorArr[id]['tipEl'].removeClass('validateError'); scope.validatorArr[id]['tipEl'].removeClass('validateInit'); scope.validatorArr[id]['tipEl'].addClass('validateSuc'); scope.validatorArr[id]['tipEl'].html('<div class="triangle_icon"><div class="before"></div> <div class="after"></div></div>' + msg); } else if (isPass == -1) { scope.validatorArr[id]['state'] = 'error'; scope.validatorArr[id]['tipEl'].removeClass('validateSuc'); scope.validatorArr[id]['tipEl'].removeClass('validateInit'); scope.validatorArr[id]['tipEl'].addClass('validateError'); scope.validatorArr[id]['tipEl'].html('<div class="triangle_icon"><div class="before"></div> <div class="after"></div></div>' + msg); } } };
這個家伙里面包含了很多東西,看着龐大,其實沒有什么意義,我們來一點一點的將之剝離:
var type = cfg.type; var regexObj = cfg.regexObj; //正則相關 var rangeObj = cfg.rangeObj; //范圍驗證 var compareObj = cfg.compareObj; //范圍驗證 var ajaxObj = cfg.ajaxObj; //ajax驗證 var msg = ''; var isPass = 1; //0初始化,1成功,-1錯誤
首先,我們將配置文件中的東東給讀出來,說是配置文件,其實就是寫在標簽里面的自定義屬性了:
<input type="text" class="formValidate" data-cfg="{ ajaxObj: 'ajax.ashx|name', requred: true, type: 'chinese', initMsg: '請輸入中文名!', sucMsg: '名字正確', errorMsg: '格式錯誤' }" />
① 我這里驗證的順序首先第一步就是判斷是否必填,若是該步不能通過,下面的邏輯都不用走了:
1 //首先進行非空驗證 2 if (cfg.requred) { 3 if (el.val() == '') { 4 isPass = -1; 5 msg = '該項必填'; 6 } 7 }
PS:這里的提示信息想要更人性話需要在配置文件里面做更多的事情了
② 若是必填這塊通過了,我們就優先判斷type指定的類型(其實就是我們已經定義好的正則了):
1 //type優先 2 if (isPass == 1 && el.val().length > 0 && typeof type == 'string') { 3 var typeArr = type.split('|'); //可能包含驗證組 4 var errorArr = cfg.errorMsg.split('|'); //各個組錯誤時候對應的信息 5 for (var i = 0, len = typeArr.length; i < len; i++) { 6 var r = this.regexEnum[typeArr[i]]; 7 //測試通過 8 if (r.test(el.val())) { 9 msg = cfg.sucMsg; 10 } else { 11 isPass = -1; 12 msg = errorArr[i] ? errorArr[i] : cfg.errorMsg; 13 break; //一旦有錯誤的地方便中斷 14 } 15 } 16 }
在這里有一個技巧,因為開始我認為可能不止判斷一個東西,會有多個需要判斷的地方,比如必填與數字限制的組合:
所以我就在type中使用“|”分割id,做多次驗證,但是!!!我后面的做法直接導致了這里的做法沒有意義啦!所以這里去掉吧。
③ 若是發現我提供的正則不能滿足要求,便可以自己寫正則了:
1 //當第一步驗證通過便執行自身正則驗證 2 if (isPass == 1 && el.val().length > 0 && regexObj) { 3 //當未指定type時候,便執行頁面中的正則表達式對象 4 var r = regexObj; 5 if (r.test(el.val())) { 6 msg = cfg.sucMsg; 7 } else { 8 isPass = -1; 9 msg = cfg.errorMsg; 10 } 11 }
④ 若是以上通過的話,我們便進入下一個東西,驗證數字范圍:
1 //當第二步驗證通過便執行范圍驗證 2 if (isPass == 1 && el.val().length > 0 && rangeObj) { 3 //日期驗證暫時忽略 4 var rangeArr = rangeObj.split('|'); 5 if (rangeArr.length == 3) { 6 var _v = el.val(); 7 var _p1 = rangeArr[1]; 8 var _p2 = rangeArr[2]; 9 if (rangeArr[0] == 'num') { 10 _v = parseInt(el.val()); 11 _p1 = parseInt(rangeArr[1]); 12 _p2 = parseInt(rangeArr[2]); 13 } 14 if (_v > _p1 && _v < _p2) { 15 msg = cfg.sucMsg; 16 } else { 17 isPass = -1; 18 msg = '請填入' + rangeArr[0] + '到' + rangeArr[1] + '直接的數字'; 19 } 20 } else { 21 console.log('范圍參數錯誤'); 22 } 23 }
PS:這里只驗證了數字和字符串(字符)的范圍,其實還想驗證日期來着,但是這塊有點大,給放棄了,看看后面有必要加上沒。。。 ⑤ 范圍驗證結束后便進入我們的相等與否的驗證,典型引用就是密碼相同驗證,工資區間驗證(后面的大於前面的)
1 //執行對比運算 2 if (isPass == 1 && el.val().length > 0 && compareObj) { 3 var compareArr = compareObj.split('|'); 4 if (compareArr.length == 3) { 5 var _type = compareArr[0] 6 var _id = compareArr[1]; 7 var _flag = compareArr[2]; 8 var _v = el.val(); 9 var _cv = $('#' + _id).val(); 10 if (_type == 'num') { 11 _v = parseInt(_v); 12 _cv = parseInt(_cv); 13 } 14 15 if (_flag == '<') { 16 if (_v < _cv) { 17 msg = cfg.sucMsg; 18 } else { 19 isPass = -1; 20 msg = '該值過大'; 21 } 22 } 23 if (_flag == '>') { 24 if (_v > _cv) { 25 msg = cfg.sucMsg; 26 } else { 27 isPass = -1; 28 msg = '該值過小'; 29 } 30 } 31 if (_flag == '=') { 32 if (_v == _cv) { 33 msg = cfg.sucMsg; 34 } else { 35 isPass = -1; 36 msg = '兩次數據不一致'; 37 } 38 } 39 } else { 40 console.log('范圍參數錯誤'); 41 } 42 }
這里的提示信息,不夠友好,若是想自定義還是得在自定義屬性中做手腳,我這里就不管他了。
⑥ 最后一步,若是前面的驗證都通過,好吧,無奈我們必須進行ajax類型的驗證(驗證用戶名在數據庫是否存在):
1 //ajax驗證 2 if (isPass == 1 && el.val().length > 0 && ajaxObj) { 3 var ajaxArr = ajaxObj.split('|'); 4 if (ajaxArr.length == 2) { 5 var _url = ajaxArr[0]; 6 var _param = {}; 7 _param[ajaxArr[1]] = el.val(); 8 $.get(_url, _param, function (data) { 9 if (typeof data == 'string') 10 data = eval('(' + data + ')'); 11 if (data.retcode == '0') { 12 msg = cfg.sucMsg; 13 } else { 14 isPass = -1; 15 msg = data.msg; 16 } 17 setResult(that, isPass); 18 }); 19 return false; //在此中斷后續操作 20 } 21 }
注意:我這里對后端傳來的格式做了強制性的約束:
{retcode: 0, msg: '', data: null} 必須是這個樣子的,retcode為0就是正確的情況,否則便讀取msg的數據 注意,msg可能會是數組,我這里還有一定問題
以上便是完整的驗證邏輯,完了文本類型的驗證估計也差不多了,最后附上驗證后面的函數:
1 function setResult(scope, isPass) { 2 if (msg == '') isPass = 0; 3 if (isPass == 0) { 4 scope.validatorArr[id]['state'] = 'init'; 5 scope.validatorArr[id]['tipEl'].removeClass('validateError'); 6 scope.validatorArr[id]['tipEl'].removeClass('validateSuc'); 7 scope.validatorArr[id]['tipEl'].addClass('validateInit'); 8 scope.validatorArr[id]['tipEl'].html('<div class="triangle_icon"><div class="before"></div><div class="after"></div></div>' + cfg.initMsg); 9 } else if (isPass == 1) { 10 scope.validatorArr[id]['state'] = 'success'; 11 scope.validatorArr[id]['tipEl'].removeClass('validateError'); 12 scope.validatorArr[id]['tipEl'].removeClass('validateInit'); 13 scope.validatorArr[id]['tipEl'].addClass('validateSuc'); 14 scope.validatorArr[id]['tipEl'].html('<div class="triangle_icon"><div class="before"></div><div class="after"></div></div>' + msg); 15 } else if (isPass == -1) { 16 scope.validatorArr[id]['state'] = 'error'; 17 scope.validatorArr[id]['tipEl'].removeClass('validateSuc'); 18 scope.validatorArr[id]['tipEl'].removeClass('validateInit'); 19 scope.validatorArr[id]['tipEl'].addClass('validateError'); 20 scope.validatorArr[id]['tipEl'].html('<div class="triangle_icon"><div class="before"></div><div class="after"></div></div>' + msg); 21 } 22 }
我這里有個處理的不是很好的地方就是,就算驗證通過我也沒處理提示框,沒有讓其隱藏,特別是上下排列的場景,若是提示框遮住了文本框就非常不友好!
注意事項
最后,需要注意一點的就是,我們上面的cfg中還有一個check屬性,該屬性用於取消某個驗證項的驗證,所以我們在上面會看到這段代碼:
//若是沒有開啟驗證便忽略之 if (!check) { this.validatorArr[id]['state'] = 'ignore'; return false; }
至此,整個主體邏輯就說完了,我們再看看其它功能。
方法描述
我們調用init方法只是將整個表單初始化,但是並沒有驗證,比如我們在編輯頁面時候進入時希望看到驗證后的結果,於是有了以下代碼:
1 FormValidator.prototype.validatorAll = function () { 2 for (var k in this.validatorArr) { 3 var v = this.validatorArr[k]; 4 v.validate(); 5 } 6 };
添加移除某項的驗證
在復雜的表單中,比如有些項目是隱藏的,當我們展開時候我們希望驗證他,但是他隱藏時候我們希望不去驗證他,所以我們有了以下代碼,初始化不希望驗證的話需要加上check: false屬性。
1 FormValidator.prototype.removeValidator = function (id) { 2 if (id && this.validatorArr[id]) { 3 this.validatorArr[id].tipEl.remove(); //刪除提示信息 4 this.validatorArr[id]['check'] = false; //將其驗證狀態置為false 5 var s = ''; 6 } 7 }; 8 9 FormValidator.prototype.addValidator = function (id) { 10 var el = $('#' + id); 11 this.initItem(el); 12 };
獲取驗證狀態
在我們點擊提交表單時候,需要獲取整個表單的驗證狀態,所以有了以下代碼:
1 FormValidator.prototype.validatorState = function () { 2 for (var k in this.validatorArr) { 3 var v = this.validatorArr[k]; 4 if (v.state == 'error') { 5 return false; 6 } 7 } 8 return true; 9 };
最后,邊說便改,於是我們的代碼就成了這個樣子了。。。好了接下來我們來試試他靈不靈呢?
弱弱的驗證成果
我們就先在一個文本上驗證下我們的東西吧,因為代碼太長,我暫時去掉CSS代碼:
1 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 2 <html xmlns="http://www.w3.org/1999/xhtml"> 3 <head> 4 <title></title> 5 <script src="js/jquery-1.7.1.min.js" type="text/javascript"></script> 6 <script src="js/yexiaochai_formValidator.js" type="text/javascript"></script> 7 <script type="text/javascript"> 8 $(document).ready(function () { 9 var f = new FormValidator(); 10 f.init(); 11 f.validatorAll(); 12 13 var bt = $('#bt'); 14 var add = $('#add'); 15 var remove = $('#remove'); 16 var name = $('#name'); 17 var single = $('#single'); 18 19 bt.click(function () { 20 f.validatorAll(); 21 var end = f.validatorState(); 22 var s = ''; 23 }); 24 25 single.click(function () { 26 f.initItem(name.val()); 27 var s = ''; 28 }); 29 30 add.click(function () { 31 f.addValidator(name.val()); 32 var s = ''; 33 }); 34 35 remove.click(function () { 36 f.removeValidator(name.val()); 37 var s = ''; 38 }); 39 40 }); 41 </script> 42 </head> 43 <body> 44 <div class="form"> 45 <input type="text" id="name" /> 46 <input type="button" value="取消驗證" id="remove" /> 47 <input type="button" value="添加驗證" id="add" /> 48 <input type="button" value="單項驗證" id="single" /> 49 <ul> 50 <li> 51 <label> 52 用戶名: 53 </label> 54 <div class="text"> 55 <input type="text" class="formValidate" data-cfg="{ ajaxObj: 'ajax.ashx|name', requred: true, type: 'chinese',
initMsg: '請輸入中文名!', sucMsg: '名字正確', errorMsg: '格式錯誤' }" />(ajax類型測試) 56 </div> 57 </li> 58 </ul> 59 <input type="button" value="提交" id="bt" /> 60 </div> 61 </body> 62 </html>
我們這個名字的驗證有以下幾個:
1 非空驗證
2 必須是中文
3 ajax驗證
對比下他的配置信息,我們看看運行結果:
我們看到一來,我們就已經驗證了,於是我們去掉其第十一行代碼:
我們看到他只是初始化了,並未進行驗證,於是我們試試取消驗證與添加驗證(輸入文本框id即可)
取消驗證后再點擊提交,其驗證狀態便是忽略狀態了:
當添加驗證后便還原了。
最后看看我們只是為了一個名字驗證干了這些事情:
ajax的代碼
public void ProcessRequest(HttpContext context) { context.Response.ContentType = "text/html"; string[] arr_name = { "葉小釵", "一頁書", "素還真" }; var name = context.Request.QueryString["name"]; var exist = false; foreach (string v in arr_name) { if (v == name) { exist = true; break; } } string retcode = exist ? "-1" : "0"; string msg = exist ? "該用戶名已經存在" : ""; context.Response.Write("{retcode: " + retcode + ", msg: '" + msg + "', data: null}"); }
這個東西只能用恐怖來形容吧!
完整的例子
最后我們來張完整的例子結束吧:
完整的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; } /*表單相關樣式,和驗證無關,可刪除*/ .form { width: 820px; margin: 0 auto; } .form ul { list-style-type: none; padding-left: 0; } .form li > label { display: inline-block; min-width: 200px; padding-right: 14px; text-align: right; vertical-align: -2px; } .form ul .text { display: inline-block; line-height: 40px; margin-left: 10px; } /*表單相關樣式,和驗證無關,可刪除*/ </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'); var single = $('#single'); bt.click(function () { f.validatorAll(); var end = f.validatorState(); var s = ''; }); single.click(function () { f.initItem(name.val()); var s = ''; }); add.click(function () { f.addValidator(name.val()); var s = ''; }); remove.click(function () { f.removeValidator(name.val()); var s = ''; }); }); </script> </head> <body> <div class="form"> <input type="text" id="name" /> <input type="button" value="取消驗證" id="remove" /> <input type="button" value="添加驗證" id="add" /> <input type="button" value="單項驗證" id="single" /> <ul> <li> <label> 身份證:</label> <div class="text"> <input type="text" id="idCard" class="formValidate" data-cfg="{ requred: true, type: 'idCard', msgPosition: 'right', initMsg: '請輸入身份證號碼!', sucMsg: '正確', errorMsg: '該項必填|格式錯誤'}" /> </div> </li> <li> <label> 數字: </label> <div class="text"> <input type="text" id="num" class="formValidate" data-cfg="{ type: 'num'}" /> </div> </li> <li> <label> 郵件: </label> <div class="text"> <input type="text" class="formValidate" data-cfg="{ type: 'email', initMsg: '請輸入郵箱地址!'}" /> </div> </li> <li> <label> 手機: </label> <div class="text"> <input type="text" class="formValidate" data-cfg="{ type: 'phone', initMsg: '請請輸入手機號碼!'}" /> </div> </li> <li> <label> QQ: </label> <div class="text"> <input type="text" class="formValidate" data-cfg="{ regexObj: /^[1-9]*[1-9][0-9]*$/, initMsg: '請請輸入手機號碼!'}" /> </div> </li> <li> <label> 年齡要求(18-25): </label> <div class="text"> <input type="text" class="formValidate" data-cfg="{ rangeObj: 'num|18|25', initMsg: '請輸入您的年齡'}" /> </div> </li> <li> <label> 用戶名: </label> <div class="text"> <input type="text" class="formValidate" data-cfg="{ ajaxObj: 'ajax.ashx|name', requred: true, type: 'chinese', initMsg: '請輸入中文名!', sucMsg: '名字正確', errorMsg: '格式錯誤' }"/>(ajax類型測試) </div> </li> <li> <label> 密碼: </label> <div class="text"> <input type="text" id="pwd" class="formValidate" data-cfg="{ requred: true, type: 'password', msgPosition: 'right', initMsg: '請輸入密碼!', sucMsg: '正確', errorMsg: '格式錯誤'}" /> </div> </li> <li> <label> 重復密碼: </label> <div class="text"> <input type="text" id="rePwd" class="formValidate" data-cfg="{ compareObj: 'str|pwd|=', requred: true}" />(驗證對比時,應該考慮日期,字符串,數字) </div> </li> <li> <label> 工作年限/薪水范圍: </label> <div class="text"> <input type="text" id="d_start" class="formValidate" data-cfg="{ type: 'num', msgPosition: 'bottom' }" />- <input type="text" id="d_end" class="formValidate" data-cfg="{ compareObj: 'num|d_start|>', type: 'num', msgPosition: 'bottom' }" /> </div> </li> <li> <br /> <br /> <label> 學歷: </label> <div class="text"> <select id="sec" class="formValidate" data-cfg="{ requred: true, initMsg: '請選擇學歷!', sucMsg: '正確', errorMsg: '必須選擇學歷' }"> <option value="" selected="selected">請選擇</option> <option value="1">專科</option> <option value="2">本科</option> <option value="3">碩士</option> </select> </div> </li> </ul> <input type="button" value="提交" id="bt" /> </div> </body> </html>
完整的JS代碼

/// <reference path="jquery-1.7.1.min.js" /> (function ($) { var FormValidator = function () { this.regexEnum = { idCard: /^[1-9]([0-9]{14}|[0-9]{16})([0-9]|X)$/, num: /^\-?([1-9]\d*)$/, //數字 email: /^([0-9A-Za-z\-_\.]+)@([0-9a-z]+\.[a-z]{2,3}(\.[a-z]{2})?)$/, phone: /^1[3|4|5|8]\d{9}$/, chinese: /^[\u0391-\uFFE5]{2,6}$/, //2-6位中文 password: /^[a-zA-Z0-9_]{8,32}$/ //6-32位密碼驗證 }; this.validatorArr = {}; }; FormValidator.prototype.init = function () { var scope = this; $('.formValidate').each(function () { var el = $(this); scope.initItem(el); }); //each }; FormValidator.prototype.initItem = function (el, insertType) { if (typeof el == 'string') el = $('#' + el); var scope = this; var cfg = el.attr('data-cfg'); //臨時添加的驗證 if (insertType) { cfg.check = true; } //若是未開啟驗證便退出該項初始化 if (cfg.check && cfg.check == false) { return false; } if (cfg && cfg.length > 0) { cfg = eval('(' + cfg + ')'); // cfg = JSON.parse(cfg); var check = cfg.check || true, id = el.attr('id') || new Date().getTime(), initMsg = cfg.initMsg || '請填入信息', sucMsg = cfg.sucMsg || '格式正確', errorMsg = cfg.errorMsg || '請注意格式', requred = cfg.requred || false, msgPosition = cfg.msgPosition || 'right'; cfg.id = id; cfg.check = check; cfg.initMsg = initMsg; cfg.sucMsg = sucMsg; cfg.errorMsg = errorMsg; cfg.msgPosition = msgPosition; cfg.requred = requred; 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 tips = $('<div class="validateTips validateInit" id="' + id + 'Tips">' + 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); cfg.el = el; cfg.tipEl = tips; //該表單的驗證 cfg.validate = function () { scope.funcValidate(cfg); }; //會觸發驗證的事件(取消驗證后,該事件取消的話害怕引起事件丟失) el.change(function () { scope.funcValidate(cfg); }); el.focus(function () { scope.funcValidate(cfg); }); el.keyup(function () { scope.funcValidate(cfg); }); scope.validatorArr[id] = cfg; //生成相關驗證對象 } else { console.log('請輸入完整驗證信息!否則控件會產生錯誤!'); } }; FormValidator.prototype.funcValidate = function (cfg) { var id = cfg.id; var el = cfg.el; var check = cfg.check; //判斷是否開啟驗證 var that = this; //取消事件不執行下面邏輯 if (!this.validatorArr[id]) return false; //若是沒有開啟驗證便忽略之 if (!check) { this.validatorArr[id]['state'] = 'ignore'; return false; } var type = cfg.type; var regexObj = cfg.regexObj; //正則相關 var rangeObj = cfg.rangeObj; //范圍驗證 var compareObj = cfg.compareObj; //范圍驗證 var ajaxObj = cfg.ajaxObj; //ajax驗證 var msg = ''; var isPass = 1; //0初始化,1成功,-1錯誤 //首先進行非空驗證 if (cfg.requred) { if (el.val() == '') { isPass = -1; msg = '該項必填'; } } //type優先 if (isPass == 1 && el.val().length > 0 && typeof type == 'string') { var r = this.regexEnum[type]; //測試通過 if (r.test(el.val())) { msg = cfg.sucMsg; } else { isPass = -1; msg = cfg.errorMsg; } } //當第一步驗證通過便執行自身正則驗證 if (isPass == 1 && el.val().length > 0 && regexObj) { //當未指定type時候,便執行頁面中的正則表達式對象 var r = regexObj; if (r.test(el.val())) { msg = cfg.sucMsg; } else { isPass = -1; msg = cfg.errorMsg; } } //當第二步驗證通過便執行范圍驗證 if (isPass == 1 && el.val().length > 0 && rangeObj) { //日期驗證暫時忽略 var rangeArr = rangeObj.split('|'); if (rangeArr.length == 3) { var _v = el.val(); var _p1 = rangeArr[1]; var _p2 = rangeArr[2]; if (rangeArr[0] == 'num') { _v = parseInt(el.val()); _p1 = parseInt(rangeArr[1]); _p2 = parseInt(rangeArr[2]); } if (_v > _p1 && _v < _p2) { msg = cfg.sucMsg; } else { isPass = -1; msg = '請填入' + rangeArr[0] + '到' + rangeArr[1] + '直接的數字'; } } else { console.log('范圍參數錯誤'); } } //執行對比運算 if (isPass == 1 && el.val().length > 0 && compareObj) { var compareArr = compareObj.split('|'); if (compareArr.length == 3) { var _type = compareArr[0] var _id = compareArr[1]; var _flag = compareArr[2]; var _v = el.val(); var _cv = $('#' + _id).val(); if (_type == 'num') { _v = parseInt(_v); _cv = parseInt(_cv); } if (_flag == '<') { if (_v < _cv) { msg = cfg.sucMsg; } else { isPass = -1; msg = '該值過大'; } } if (_flag == '>') { if (_v > _cv) { msg = cfg.sucMsg; } else { isPass = -1; msg = '該值過小'; } } if (_flag == '=') { if (_v == _cv) { msg = cfg.sucMsg; } else { isPass = -1; msg = '兩次數據不一致'; } } } else { console.log('范圍參數錯誤'); } } //ajax驗證 if (isPass == 1 && el.val().length > 0 && ajaxObj) { var ajaxArr = ajaxObj.split('|'); if (ajaxArr.length == 2) { var _url = ajaxArr[0]; var _param = {}; _param[ajaxArr[1]] = el.val(); $.get(_url, _param, function (data) { if (typeof data == 'string') data = eval('(' + data + ')'); if (data.retcode == '0') { msg = cfg.sucMsg; } else { isPass = -1; msg = data.msg; } setResult(that, isPass); }); return false; //在此中斷后續操作 } } setResult(this, isPass); function setResult(scope, isPass) { if (msg == '') isPass = 0; if (isPass == 0) { scope.validatorArr[id]['state'] = 'init'; scope.validatorArr[id]['tipEl'].removeClass('validateError'); scope.validatorArr[id]['tipEl'].removeClass('validateSuc'); scope.validatorArr[id]['tipEl'].addClass('validateInit'); scope.validatorArr[id]['tipEl'].html('<div class="triangle_icon"><div class="before"></div><div class="after"></div></div>' + cfg.initMsg); } else if (isPass == 1) { scope.validatorArr[id]['state'] = 'success'; scope.validatorArr[id]['tipEl'].removeClass('validateError'); scope.validatorArr[id]['tipEl'].removeClass('validateInit'); scope.validatorArr[id]['tipEl'].addClass('validateSuc'); scope.validatorArr[id]['tipEl'].html('<div class="triangle_icon"><div class="before"></div><div class="after"></div></div>' + msg); } else if (isPass == -1) { scope.validatorArr[id]['state'] = 'error'; scope.validatorArr[id]['tipEl'].removeClass('validateSuc'); scope.validatorArr[id]['tipEl'].removeClass('validateInit'); scope.validatorArr[id]['tipEl'].addClass('validateError'); scope.validatorArr[id]['tipEl'].html('<div class="triangle_icon"><div class="before"></div><div class="after"></div></div>' + msg); } } }; FormValidator.prototype.validatorAll = function () { for (var k in this.validatorArr) { var v = this.validatorArr[k]; v.validate(); } }; FormValidator.prototype.removeValidator = function (id) { if (id && this.validatorArr[id]) { this.validatorArr[id].tipEl.remove(); //刪除提示信息 this.validatorArr[id]['check'] = false; //將其驗證狀態置為false var s = ''; } }; FormValidator.prototype.addValidator = function (id) { var el = $('#' + id); this.initItem(el, 'add'); }; FormValidator.prototype.validatorState = function () { for (var k in this.validatorArr) { var v = this.validatorArr[k]; if (v.state == 'error') { return false; } } return true; }; window.FormValidator = FormValidator; })(jQuery);
結語
經過2天的奮戰,終於完成了,雖然千瘡百孔,但是作為練手或者學習的工具還是很不錯的,希望對各位朋友有幫助。
若是您發現任何問題,請回復之,我有時間便予以修改,多謝啦!
若是你覺得這篇文章不錯請點推薦哦