您的位置:首页 > 其它

老大让我写个表单验证的插件,市面上的表单验证插件不再少数。但是老大让我写肯定是想锻炼我

2015-09-07 17:43 288 查看
作为一个初学者我只能写到这个样子了,对于内存,优化什么的也顾不了哪些了,勉勉强强算是实现了功能,还有很多漏洞。我写的第一个插件,不为别的留下来做个纪念。


//给jq添加一个verfiable方法

//2.2版本将验证方法分装成函数模块,通过属性来调用相对应的验证函数

//2.3TODO增加刷新验证的功能,修复动态增加输入框而不能进行验证的问题(setTnterval),修复表单提交的状态

//2.4增加用户指定元素显示错误的功能,将显示错误的代码提取出来。

//2.5功能模块化分为:初始化-执行验证模块-元素绑定函数模块-函数验证模块-验证结果处理模块-表单提交模块

//2.6优化验证函数的返回值,删除判断是否成功的代码。

//2.7将函数模块封装成一个对象,改用brack case代替value

//2.8添加表单提交的时的判断,其中有一个未通过验证则,表单不能提交

//2.9添加ajax远程验证,ajax作为特殊验证单独处理,未放在funModel内,而与其他条件并行验证

//2.10增加日期验证,调优submit提交验证

//2.11绑定select,checkbox,radios的事件,在点击提交按钮时验证这三种元素

//2.12将一些公用的部分提出来作为工具函数

//2.13表单序列化

/*data-rules中的属性氛围str,obj两种类型

data-rules={

id://用于提交表单提交时提醒用户该id出验证失败(如果用户自定义验证失败的函数,次属性可以省略,否则不可省略)

success://验证通过时的验证信息

userEle://用户指定的提示元素

isEmpt:str//验证是否为空

isChinese://是否为中文

isNumber://判断是否为数字

isPosint://是否为正整数

isEmall: //检验邮箱

isPhone: //检验电话号码

isUrl: //判断网址

isLong:{ //验证长度

min://最大长度

max://最小长度

tip://验证不通过时的提示信息

}

isID: {

minAge: 最小年龄

maxAge: 最大年龄

sex: ['male', 'female'] male 男性 female 女性

province: 省份名称,如北京、天津等

tip://提示信息

}

范围比较

isRange

{

* type: ['length','number', 'integer'] length 长度比较 number 数值比较 integer 整数数值比较(包含0)

min: 最小值

max: 最大值

tip:

}

uRegexp:{ //用户自定义正则表达式

* rule:'^1[3|4|5|8|7]\\d{9}$'//正则表达式格式必须使用new regexp的格式

igm://参数

tip://错误提示信息

}

uFunction:function(d){} //用户自定义验证函数

compare:{

* to://要比较的元素选择器

* condition://比较符号

tip://提示信息

}

vAjax:{

* url: // 远程校验的网址

* type:['POST','GET'] 方法,默认为post

* data:提交给服务器端的数据,可以是key1=value1&key2=value2、{key1:value1}、function(){return {key1:value1}}等形式

* dataType:['text','json', 'html']等

* verify:函数,用来校验返回数据,如果返回true,说明校验成功,如果返回false,说明校验失败。如果没有这个函数,则返回的数据为true或者'true'时认为成功,其他都为失败

tip:校验码填写不正确

}

checkbox:{

min:

max:

tip:

}

radio:str

select:str

}

设置修改提示元素的样式:

验证通过的class:success

验证不通过的class:error

TODO: 1.下拉表,单选框,多选框。

2.ajax远程验证

data-submit={

success:fun() 表单验证通过时的函数

error:fun() 表单验证未通过的时候执行的函数

}

*/

(function($){

$.fn.verfiable = function()

{

/*********************************初始化数据*******************************/

var form = $(this);

var all = form.find("[data-rules]"); //找出form下的所有需要验证的的元素

var ele = all.filter('[type=checkbox], [type=radio], select') //过滤出需要验证的checkbox,select,radio

var inps = all.not(ele) //剔除ele,剩下的则是输入框

var iniVal = { //定义初始值

success:"通过!",

error:"验证失败!"

}

/*********************************初始化数据*******************************/

/*********************************给每个需要验证的绑定函数*******************************/

var yanzhen = function (form){

inps.each(function(){

$(this).unbind("blur").bind("blur", function() //给每个input绑定失去焦点的函数

{

var data = $(this).val(); //此处获取val值,避免验证中重复获取

var rules = getRule(this,'data-rules'); //使用工具函数获取rules对象

var TipShow = getTipEle(this, rules); //用来显示提示信息(成功或失败)的元素

var TipTxt; //存放提示信息

//绑定获得焦点时函数,去除上次的错误提示start

$(this).unbind("focus").bind("focus",function()

{

if ($(this).next().hasClass("addEle")) { //如果是动态添加的tipshow则删除

$(this).next().remove();

} else if (rules.userEle || $(this).next().hasClass("userEle")) { //否则清除html内容

if ($(TipShow).hasClass('error')){

$(TipShow).removeClass("error");

} else {

$(TipShow.removeClass("success"));

}

$(TipShow).html("");

}

})

//绑定获得焦点时函数,去除上次的错误提示end

//遍历rules对象中的属性

for (var i in rules) { //将对象的每个属性都执行一遍对应的函数

var fun = eval("funModel."+i); //将rules的各个属性转化成函数模块funModel的属性

if (fun == undefined) { //如果函数库中没有对应的验证函数(保函ajax的情况),则跳过不验证次属性

continue;

};

//fun!=undefined说明funModel中有次对应的函数,且不是vAjax时则应执行此函数

var result = fun(rules[i], data ,this); //将rules穿参进去,执行每个验证规则的方法

TipTxt = getTipTxt(this, rules[i]);

/*根据返回值判断验证是否成功start*/

if (result===false) { //返回为false则验证不通过

TipShow.addClass("error").html(TipTxt);//将显示错误信息的元素添加class样式

this.setAttribute('data-pass', "false"); //标记为验证不通过

return false;

}

}

//执行到这里说明前方验证已通过,返回值不为false则视为成功 如果有ajax则还需进行ajax验证

//如果有ajax验证这一项则进行

if (rules.vAjax) {

var resultA;

//发动ajax请求

(function(R,T){

$.ajax({url:R.vAjax.url,type:R.vAjax.type,data:T.name+"="+data,async: true,success:function(data){

if(R.vAjax.fun){ //如果设置了验证函数,则将返回值穿入函数中验证该函数返回的为true或者false

resultA=R.vAjax.fun(data);

} else { //没设置验证函数则返回的必须是true或者false

resultA=data;

}

if (resultA == false) { //当验证失败时

console.log("ajax失败")

if (R.vAjax.tip) {

TipShow.addClass("error").html(R.vAjax.tip);

} else {

TipShow.addClass("error").html(iniVal.error);

}

T.setAttribute('data-pass', "false");//设置成功标记

} else { //验证成功时

if (R.success) {

TipShow.addClass("success").html(R.success);

} else {

TipShow.addClass("success").html(iniVal.success);

}

T.setAttribute('data-pass', "true");//设置成功标记

}

}})

})(rules, this)

/*******ajax远程验证结束*********/

} else { //如果没有

if (rules.success!=undefined) { //判断用户是否自定义提示信息

TipTxt = rules.success;

} else {

TipTxt =iniVal.success;

}

TipShow.addClass("success").html(TipTxt);

this.setAttribute('data-pass', "true");//设置成功标记

return true;

}

})

})

}

/*********************************绑定验证并调用函数*******************************/

/*********************************验证函数区域*******************************/

var funModel = {

//验证是否为空

isEmpt : function (Rule, data) //这里函数内的this指向的是window,所以需要将this一参数的形式传进来,

{

if ($.trim(data) == "") {

return false;

}

},

//验证长度是否通过

isLong : function (Rule, data)

{

if (data.length < Rule.min || data.length > Rule.max) {

return false;

}

},

//验证邮箱

isEmall : function (Rule, data)

{

var RegExp = /^((([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))@((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|\.|-|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)((com(\.[a-z]{2})?)|net|cn|cc)$/i;

if(!RegExp.test(data)){

return false;

}

},

//验证手机号

isPhone : function ( Rule, data)

{

if(!/^1[3|4|5|8|7]\d{9}$/.test(data)){

return false;

}

},

//检测是否中文

isChinese : function (Rule, data)

{

if(!/^[\u4e00-\u9fa5]+$/.test(data)){

return false;

}

},

//验证是否为数字

isNumber : function(Rule, data)

{

if (isNaN(data)) {

return false;

};

},

//验证是否为为金额格式

isPosint: function(Rule, data)

{

if (/^[1-9](\d+)?$/.test(data)) {

return false;

};

},

//验证是否为url

isUrl : function (Rule, data)

{

var regexp = /^(https?|ftp):\/\/(((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:)*@)?(((\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5]))|((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?)(:\d*)?)(\/((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)+(\/(([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)*)*)?)?(\?((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|[\uE000-\uF8FF]|\/|\?)*)?(\#((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|\/|\?)*)?$/i

if (!regexp.test(data)) {

return false;

}

},

//范围值检验

isRange: function(rule, val){

if (undefined === rule.min) {

rule.min = Number.MIN_VALUE;

}

if (undefined === rule.max) {

rule.max = Number.MAX_VALUE;

}

switch(rule.type) {

case 'integer':

if( ! /^-?\d+$/.test(val)){

return false;

}

return val <= rule.max && val >= rule.min;

break;

case 'length':

return val.length <= rule.max && val.length >= rule.min;

break;

case 'number':

if(!isNaN(val)){

return val <= rule.max && val >= rule.min;

}else{

return false;

}

break;

}

},

//验证身份证

isID : function(rule, data)

{

if (!data) return rule.tip;

var len = data.length;

if (len != 15 && len != 18) {

return false;

}

// 检测基本格式是否正确

if (!/^(\d{15})|(\d{17}([0-9xX]))$/.test(data)) {

return false;

}

// 根据校验规则检查身份证合法性

if (len == 18) {

var total = 0, v = [1,0,'X',9,8,7,6,5,4,3,2], mod, rightCode;

$.each([7, 9, 10, 5, 8, 4, 2, 1, 6, 3], function(i){

if (i < 7) {

total += ((parseInt(data.charAt(i)) + parseInt(data.charAt(i+10))) * this);

} else {

total += (parseInt(data.charAt(i))) * this;

}

});

mod = total % 11;

rightCode = v[mod] + '';

if (data.charAt(17).toLowerCase() != rightCode.toLowerCase()) {

return false;

}

}

// 校验地区的合法性

if (!this.cities) {

this.cities = {11:'北京',12:'天津',13:'河北',14:'山西',15:'内蒙古',21:'辽宁',22:'吉林',23:'黑龙江 ',31:'上海',32:'江苏',33:'浙江',34:'安徽',35:'福建',36:'江西',37:'山东',41:'河南',42:'湖北',43:'湖南',44:'广东',45:'广西',46:'海南',50:'重庆',51:'四川',52:'贵州',53:'云南',54:'西藏 ',61:'陕西',62:'甘肃',63:'青海',64:'宁夏',65:'新疆',71:'台湾',81:'香港',82:'澳门',91:'国外'};

}

if (!(data.substr(0, 2) in this.cities)) {

return false;

}

// 检测限制的地区是否正确

if (this.cities[data.substr(0,2)] != rule.province) {

return false;

}

// 检查性别

if (rule.sex) {

var tag = data.substr(len == 15 ? len -1 : len - 2, 1);

if (tag % 2 == 0) {

if (rule.sex != 'female') {

return false;

}

} else {

if (rule.sex != 'male') {

return false;

}

}

}

// 检测生日的合法性

var yearLen = len == 15 ? 2 : 4,

year = parseInt(len == 2 ? '19' + data.substr(6, yearLen) : data.substr(6, 4), 10),

month = parseInt(data.substr(6 + yearLen, 2), 10),

day = parseInt(data.substr(8 + yearLen, 2), 10),

d = new Date(year, month - 1, day);

if (d.getFullYear() != year || d.getMonth() != month - 1 || d.getDate() != day) {

return false;

}

var offDay = parseInt((new Date().getTime() - d.getTime())/(1000*3600*24));

// 检查最小年龄

console.log("开始")

if (rule.minAge) {

if (offDay < 365 * rule.minAge) {

return false;

}

}

// 检查最大年龄

if (rule.maxAge) {

if (offDay > 365 * rule.maxAge) {

return false;

}

}

},

//验证是否为日期正则表达式

isDate : function(rule, val) {

var _dateReg = /^([12][0-9]{3})[\-\/\_\.\s]?(0?[1-9]|1[012])[\-\/\_\.\s]?(0?[1-9]|[12][0-9]|3[01])$/;

var ms = _dateReg.exec(val), date;//类似于test方法,匹配成功返回的为一个结果ji数组,失败则返回null

if (ms) { //若正则表达式匹配成功则执行

var y = parseInt(ms[1], 10), m = parseInt(ms[2], 10) - 1, d = parseInt(ms[3], 10);//取出年月日

try {

return new Date(y, m, d);//返回一个日期

} catch (e) {

return false;

}

}

return false;

},

//isDate:{

// min:

// max:

// tip:

// }

ruleDate:function(rule, val){

var date = funModel.isDate(rule,val);

if (date == false) {

return false;

}

// 检查最小数

if (rule.min || rule.max) {

var now = new Date();

if (rule.min) {

if (!isNaN(rule.min)) {

if ( (date.getTime() - now.getTime())/1000 < rule.min ) {

return false;

}

} else {

var min = funModel.isDate(rule, rule.min);

// if (!min) {

// return hapj.log.error('hapj.ui.verifiable date format wrong');

// }

console.log(min)

if (date.getTime() < min.getTime()) {

return false;

}

}

}

if (rule.max) {

if (!isNaN(rule.max)) {

if ( (date.getTime() - now.getTime())/1000 > rule.max ) {

return false;

}

} else {

var max = funModel.isDate(rule, rule.max);

// if (!max) {

// return hapj.log.error('hapj.ui.verifiable date format wrong');

// }

if (date.getTime() > max.getTime()) {

return false;

}

}

}

}

return true;

},

//比较验证

compare: function(rule, data) {

var cVal = $(rule.to).val();//to

if (!rule.condition) { //condition去除字符串两端的空格

rule.condition = '=';

}

switch(rule.condition) {

case '=':

case 'equal':

return data == cVal;

case '!=':

case '<>':

case 'notEqual':

return data != cVal;

case '>':

case 'great':

return data > cVal;

case '<':

case 'less':

return data < cVal;

case '>=':

case 'notGreat':

return data >= cVal;

case '<=':

case 'notLess':

return data <= cVal;

default:

return H.log.error('hapj.ui.verifiable the condition(' + rule.condition + ') is not defined');

}

},

//自定义正则表达式

uRegexp:function(rule ,data){

var regexp = new RegExp (rule.rule,rule.igm);

if (!regexp.test(data)) {

return false;

};

},

//自定义验证函数

uFunction:function(rule ,data,T){

if(T.type=="checkbox"||T.type=="radio"){

console.log("单选复选框啊")

}

return rule(data);

}

}

/*********************************验证函数区域end*******************************/

/*********************checkbox,radio,select*****************************/

function checkboxs(form){

var check = ele.filter(":checkbox"); //找出需要检验的多选框

if (check.length == 0) {//如果没有需要检验的多选框则退出

return true;

}

check.each(function(){

var T = $(this)

var rule = T.attr("data-rules");

rule= eval('['+rule+']')[0];

var cname = check.attr("name"); //取出name

var checks = form.find("[name="+cname+"]");//找出同name的所有复选框

checks = checks.filter(":checked"); //找出所有的被选中的复选框

if (rule.checkbox.min > checks.length || rule.checkbox.max < checks.length) {

//验证不通过

T.attr("data-pass","false");

} else {

T.attr("data-pass","true");

}

})

}

function radios(form){

var radios = ele.filter(":radio"); //找出所有需要检验的单选框

if (radios.length == 0) {

return true;

};

for(var i=0;i<radios.length;i++){

var name = radios[i].name;

var nameR = form.find("[name="+name+"]");//找出所有同name的单选

nameR = nameR.filter(":checked"); //查找被选中的元素

if(nameR.length == 0){// 如果没有元素被选中则验证不通过

radios[i].setAttribute("data-pass","false");

} else {

radios[i].setAttribute("data-pass","true") //如果有元素被选中则 表示通过

}

}

}

function selects(){

var selects = ele.filter("select"); //找出所有的下拉框

if (selects.length == 0) {

return true;

}

selects.each(function(){

console.log(this.value)

if (this.value == "" ||this.value == undefined) {//只要select的值不为""和undefined则验证通过

this.setAttribute("data-pass",false);

} else {

this.setAttribute("data-pass",true);

}

})

}

/***********************************工具函数start**********************************/

function getRule(elem, str){ //该函数用于获取rule对象

var dar = $(elem).attr(str);

var rules = eval('['+dar+']')[0];

return rules;

}

function getTipEle(elem, rules){//获取显示错误信息的元素

var addEle = "<span class='addEle'></span>"; //自动添加错误提示的html代码

var Tipshow;

if (rules.userEle) { //如果用户有指定错误的显示位置

TipShow = $(rules.userEle);

} else {

TipShow = $(addEle).insertAfter($(elem));//自己添加显示错的元素

}

return TipShow;

//控制错误信息在哪个里显示end

}

function getTipTxt(elem, rule){//获取错误提示信息

var TipTxt;

if (rule instanceof Object) {//如果是个对象,则判断用户是否自定义提示信息,有则显示自定义,无则显示初始值。

if (rule.tip) {

TipTxt = rule.tip;

} else {

TipTxt = iniVal.error;

}

} else {

//若为字符串类型,说明该属性的值是提示文本则将问题显示出来

TipTxt = rule;

}

return TipTxt;

}

//表单序列化

function getForm(form){

var datas = form.find("[name]");

var str="";

$.each(datas,function(i,v){

str=str+"&"+v.name+"="+v.value;

})

str=str.slice(1);

return str;

}

/***********************************工具函数end**********************************/

/*****************submit表单提交*******************************************/

//表单提交时候的验证函数

function vSubmit()

{

radios(form);

selects(form);

checkboxs(form);

for(var i=0;i<all.length;i++){

if($(all[i]).attr("data-pass") != 'true'){

var rule = getRule(all[i], "data-rules");

if (rule.id == undefined) {//如果忘了写id则同样不能提交

return "请将表单填写完整";

};

return rule.id;//返回验证失败的元素的data-rule.id属性,便于用户查找是哪里出了错

}

}

return true;//验证成功则放回true了,验证失败则将提示信息返回

}

//表单提交时候的对话框

function tanChuang(){//生成弹窗

$("<div class='v_daiLog' style='display:none;position:fixed;top:0;left:0;width:100%;height:100%;background-color:rgba(200,200,200,.8)'></div>").appendTo("body");

$("<div class='v_mask'><p></p></div>").appendTo(".v_daiLog")

var mask = $(".v_mask");

mask.append("<button class='v_close'>关闭</button>");

mask.css({width:300,height:200,position:"fixed",textAlign:"center",

backgroundColor:"#999",top:($(window).height()-300)/2,left:($(window).width()-200)/2})

$(".v_mask .v_close").css({display:"block",width:"100%"})

.click(function(){

$(".v_daiLog").css("display",'none');

})

}

//先判断用户是否制定submit

if($("[data-submit]").length!=0){

// form.attr("onsubmit","return false");//如果用户设定了.submit则说明用户不希望原生提交,则阻止原生提交方式

form.find("[data-submit]").unbind("click").click(function(){

var submit = getRule(this, "data-submit"); //获取data-submit对形象

if($(".v_mask").length==0 && submit.isDefault==true){//如果没有弹窗并且用户要使用默认弹窗则生成一个弹窗

tanChuang();

}

var p = vSubmit();

if (p != true) {

if (submit.isDefault) {//如果制指定了要用默认样式才使用

$(".v_daiLog").css("display","block");

$(".v_mask p").text(p);

}

submit.error();

return false;

}

var string = getForm(form)//获取表单数据

$.ajax({url:form[0].action,data:string,type:form[0].method,success:function(data){

submit.success();

},error:function(){

alert("服务器无响应,请重新提交");

}})

})

} else { //否则用户希望用原生方式提交

if($(".v_mask").length==0){

tanChuang();

}

$("[type = submit]").unbind("click").click(function(){

if($(".v_mask").length==0 && submit.isDefault==true){//如果没有弹窗并且用户要使用默认弹窗则生成一个弹窗

tanChuang();

}

var p = vSubmit();

if(p != true){

//弹出遮罩层显示结果

$(".v_daiLog").css("display","block");

$(".v_mask p").text(p);//更具元素id属性,提示用户是哪一个元素验证失败

return false;

} else {

alert("可以提交!!!!!")

form.attr("onsubmit","return true");

}

})

}

/*****************submit表单提交*******************************************/

yanzhen(form);

}

})(jQuery);
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: