手把手教你自己寫一個js表單驗證框架
其實我自己也就能簡單用用js而已,但是呢,相對很多初學者來說多懂了點Know How所以斗膽孟浪一下,將一些所得記錄下來,以供更多的初學者能夠知道一個東西的實現過程,省去在源碼里摸索的過程。
在表單程序中,在頁面上需要很多的Js代碼來驗證表單,每一個field是否必須填寫,是否只能是數字,是否需要ajax到遠程驗證,blablabla。如果一個一個單獨寫勢必非常的繁瑣,所以我們的第一個目標就是構建一個類似DSL的東西,用表述的語句而非控制語句來實現驗證。
其次一個個單獨寫的話還有一個問題就是必須全部驗證通過才能提交,但是單獨驗證會因為這個特征而增加很多額外的控制代碼,且經常會驗證不全面。所以第二個目標就是能夠全面的整合整個驗證的過程。
最后不能是一個無法擴展的一切寫死的實現,必要的擴展性還是要的。
首先,我們需要一個能夠描述對字段驗證的類
function Field(params){ this.field_id=params.fid; //要驗證的字段的ID this.validators=params.val; //驗證器對象數組 this.on_suc=params.suc; //當驗證成功的時候執行的事件 this.on_error=params.err; //當驗證失敗的時候執行的事件 this.checked=false; //是否通過驗證 }
關于驗證器對象我們在后面來討論,接下來我們擴展這個類,加入validate方法
Field.prototype.validate=function(){ //循環每一個驗證器 for(item in this.validators){ //給驗證器附加驗證成功和驗證失敗的回調事件 this.set_callback(this.validators[item]); //執行驗證器上的Validate方法,驗證是否符合規則 if(!this.validators[item].validate(this.data())){ break; //一旦任意一個驗證器失敗就停止 } } }
再加入一個獲取字段值的方法:
//獲取字段值的方法 Field.prototype.data=function(){ return document.getElementById(this.field_id).value; }
設置驗證器回調函數的方法set_callback如下:
Field.prototype.set_callback=function(val){ var self=this; //換一個名字來存儲this,不然函數的閉包中會覆蓋這個名字 val.on_suc=function(){ //驗證成功執行的方法 self.checked=true; //將字段設置為驗證成功 self.on_suc(val.tips); //執行驗證成功的事件 } val.on_error=function(){ //驗證失敗的時候執行的方法 self.checked=false; //字段設置為驗證失敗 self.on_error(val.tips);//執行驗證失敗的事件 } }
接下來我們就來看看驗證器,驗證器是真正執行驗證過程的類,根據一般的驗證過程,我們可以將其分類成,長度驗證(包括必填驗證),正則表達式驗證,自定義函數驗證,Ajax遠程驗證這幾種,所以我們定義這幾種驗證器類,Ajax遠程驗證為了方便引用了jQuery,其他部分也有用到:
//長度驗證的驗證器類 function Len_val(min_l,max_l,tip){ this.min_v=min_l; this.max_v=max_l; this.tips=tip; this.on_suc=null; this.on_error=null; } Len_val.prototype.validate=function(fd){ if(fd.length<this.min_v||fd.length>this.max_v){ this.on_error(); return false; } this.on_suc(); return true; } //正則表達式驗證器 function Exp_val(expresion,tip){ this.exps=expresion; this.tips=tip; this.on_suc=null; this.on_error=null; } Exp_val.prototype.validate=function(fd){ if(!fd){ this.on_suc(); return true; } if(this.exps.test(fd)){ this.on_suc(); return true; }else{ this.on_error(); return false; } } //遠程驗證器 function Remote_val(url,tip){ this.p_url=url; this.tips=tip; this.on_suc=null; this.on_error=null; } Remote_val.prototype.validate=function(fd){ var self=this; $.post(this.p_url,{f:fd}, function(data){ if(data.rs){ self.on_suc(); return; }else{ self.on_error(); } },"json" ); return false; } //自定義函數驗證器 function Man_val(tip,func){ this.tips=tip; this.val_func=func; this.on_suc=null; this.on_error=null; } Man_val.prototype.validate=function(fd){ if(this.val_func(fd)){ this.on_suc(); }else{ this.on_error(); } }
最后我們用一個userform的類來做一個入口,在構造的時候傳入Field對象的列表,并且將每一個控件的onblur事件綁定到validate的包裝器上
function UserForm(items){ this.f_item=items; //把字段驗證對象數組復制給屬性 for(idx=0;idx<this.f_item.length;idx++){ //循環數組 var fc=this.get_check(this.f_item[idx]); //獲取封裝后的回調事件 $("#"+this.f_item[idx].field_id).blur(fc); //綁定到控件上 } } //綁定驗證事件的處理器,為了避開循環對閉包的影響 UserForm.prototype.get_check=function(v){ return function(){ //返回包裝了調用validate方法的事件 v.validate(); } }
接下來需要定義一個方法來綁定提交按鈕的onclick事件:
//綁定提交事件到元件 UserForm.prototype.set_submit=function(bid,bind){ var self=this; $("#"+bid).click( function(){ if(self.validate()){ bind(); } } ); }
這里提到了一個UserForm的validate方法,如下:
//驗證所有的字段 UserForm.prototype.validate=function(){ for(idx in this.f_item){ //循環每一個驗證器 this.f_item[idx].validate(); //再檢測一遍 if(!this.f_item[idx].checked){ return false; //如果錯誤就返回失敗,阻止提交 } } return true; //一個都沒錯就返回成功執行提交 }
最后用一個例子來看看怎么用:
<html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/> <title>test</title> <script type="text/javascript" src="jquery-1.4.2.min.js"></script> <script type="text/javascript" src="kernel.js"></script> <script type="text/javascript"> var form; $( function(){ var uf=new UserForm([new Field({ fid:"f1", val:[new Len_val(1,5,"長度錯誤"),new Exp_val(v_int,"不是數字")], suc:function(text){ $('t1').val(''); $('t1').attr('class','suc'); }, err:function(text){ ('t1').val(text); $('t1').attr('class','error'); } }) ]); uf.set_submit( "bt", function(form){ alert("表單已經提交了"); } ); } ); </script> <style> .suc { background-color:#00ff00;} .error { background-color:#ff0000;} </style> </head> <body> <input type="text" id="f1" name="f1"/><span id="t1"></span><br/> <input type="button" id="bt" value="提交"/> </body> </html>
要注意的地方就是在循環中使用閉包會茶幾,必須用一個方法來代理一下,呵呵 希望對初學js但是還不知道該做點什么怎么做的朋友能有所幫助