各位加了一天班累了吧?那我们来继续未完的表单验证吧
前言
接着昨天的写:工作了一个星期各位一定累了吧,那我们一起来表单验证一番吧!
因为昨天写到后面确实写不动了,就停下了,今天我们继续吧,看看能不能解决昨天提出的几个问题,由于今天看了下别人写的插件,在里面找到了一些很不错的点子,这里也应用起来了,慢慢改造我们的程序吧。
现状
经过今天的奋战,我们的界面变成了这个样子啦:
代码变成了这个样子:
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天的奋战,终于完成了,虽然千疮百孔,但是作为练手或者学习的工具还是很不错的,希望对各位朋友有帮助。
若是您发现任何问题,请回复之,我有时间便予以修改,多谢啦!
若是你觉得这篇文章不错请点推荐哦