從表單校驗(yàn)看JavaScript策略模式的使用詳解
眾所周知的是,表單確實(shí)在前端,唔,或者說在網(wǎng)頁中占有不小的比重。事實(shí)上,幾乎每一個(gè)中大型網(wǎng)站都會(huì)有“登錄注冊(cè)”以驗(yàn)證用戶信息、防止一些不可名狀的隱患。。。
那么表單的優(yōu)劣就成了前端開發(fā)者急需解決的問題。其實(shí)我更愿意稱為“代碼的可讀性”或“可復(fù)用性”以及“是否冗雜”。
表單也有“優(yōu)劣”?你在開玩笑嘛?
我想你可以認(rèn)真看下下面的代碼,它用到了一些“新知識(shí)”:
<form action="xxx" id="registerForm"> 請(qǐng)輸入用戶名:<input type="text" name="userName" id="name" /> 請(qǐng)輸入密碼:<input type="text" name="password" id="pass" /> 請(qǐng)輸入手機(jī)號(hào):<input type="text" name="phoneNumber" id="phone" /> <button>提交</button> </form>
用戶名、密碼、手機(jī)號(hào)這應(yīng)該是表單中最常見的了,好,我們就以此分析!
上面這些只是簡單的演示效果,你完全可以用css的valid/invalid、HTML5的required/pattern來配合完成。
<script> var registerForm=document.getElementById('registerForm') registerForm.onsubmit=function(){ if(registerForm.userName.value==''){ document.getElementById("name").setCustomValidity('用戶名不能為空'); return false; } if(registerForm.password.value.length<6){ document.getElementById("pass").setCustomValidity('密碼長度不能少于6位'); return false; } if(!/(^1[3|5|8][0-9]{9}$)/.test(registerForm.phoneNumber.value)){ document.getElementById("phone").setCustomValidity('手機(jī)號(hào)碼格式不正確'); return false; } } </script>
但即使這樣,你也不會(huì)覺得它很完美 —— 現(xiàn)在表單只有三條,如果某一天它增加到了N條,即使是「復(fù)制粘貼」也拯救不了你!
就在這時(shí),你想到了 策略模式 (看,JS總是會(huì)讓你“靈光一現(xiàn)”)
說起策略模式,很自然地,要遵循 暴露接口和實(shí)現(xiàn)邏輯分離 的原則。
策略模式指的是定義一系列的算法,把它們一個(gè)個(gè)封裝起來。將不變的部分和變化的部分隔開是每個(gè)設(shè)計(jì)模式的主題,策略模式也不例外,
策略模式的目的就是將算法的使用與算法的實(shí)現(xiàn)分離開來。
一個(gè)基于策略模式的程序至少由兩部分組成。第一個(gè)部分是一組策略類,策略類封裝了具體的算法,并負(fù)責(zé)具體的計(jì)算過程。第二個(gè)部分是環(huán)境類 Context,Context 接受客戶的請(qǐng)求,隨后把請(qǐng)求委托給某一個(gè)策略類。要做到這點(diǎn),說明 Context 中要維持對(duì)某個(gè)策略對(duì)象的引用
——《JavaScript設(shè)計(jì)模式與開發(fā)實(shí)踐》
那么,第一步我們很顯然要把這些校驗(yàn)邏輯都封裝成【策略對(duì)象】:
var strategies={ isNoneEmpty:function(value,errorMsg){ if(value===''){ return errorMsg; } }, minLength:function(value,length,errorMsg){ if(value.length<length){ return errorMsg; } }, isMobile:function(value,errorMsg){ if(!/(^1[3|5|8][0-9]{9}$)/.test(value)){ return errorMsg; } } };
接下來我們要實(shí)現(xiàn)一個(gè)“暴露出去的”、“作為調(diào)用的”方法類 —— 它將作為context(上下文),負(fù)責(zé)接收用戶的請(qǐng)求并委托給驗(yàn)證對(duì)象stratrgies:
var Validator=function(){ this.cache=[]; //用于保存接收到的校驗(yàn)規(guī)則 }; Validator.prototype.add=function(dom,rule,errorMsg){ var ary=rule.split(':'); this.cache.push(function(){ var strategy=ary.shift(); ary.unshift(dom.value); ary.push(errorMsg); return strategies[strategy].apply(dom,ary); //調(diào)用strategies對(duì)象的指定方法對(duì)象,并規(guī)定在函數(shù)對(duì)象內(nèi)部this指向dom元素,ary作為參數(shù)傳入 }); }; Validator.prototype.start=function(){ for(var i=0,validatorFunc;validatorFunc=this.cache[i++];){ var msg=validatorFunc(); if(msg){ return msg; } } }
使用:
var validataFunc=function(){ var validator=new Validator(); //添加校驗(yàn)規(guī)則 validator.add(registerForm.userName,'isNoneEmpty','用戶名不能為空'); validator.add(registerForm.password,'minLength:6','密碼長度不能少于6位'); validator.add(registerForm.phoneNumber,'isMobile','手機(jī)號(hào)碼格式不正確'); var errMsg=validator.start(); //獲得校驗(yàn)結(jié)果 return errorMsg; //返回 } var registerForm=document.getElementById('registerForm') registerForm.onsubmit=function(){ var errorMsg=validataFunc(); if(errorMsg){ //觸發(fā)錯(cuò)誤提示 return false; //并阻止表單提交 } }
我們可以看到的是:當(dāng)我們往 validator 對(duì)象里添加完一系列的校驗(yàn)規(guī)則之后,會(huì)調(diào)用 validator.start()
方法來啟動(dòng)校驗(yàn)。如果 validator.start()
返回了一個(gè)確切的 errorMsg 字符串當(dāng)作返回值,說明該次校驗(yàn)沒有通過,此時(shí)需讓 registerForm.onsubmit
方法返回 false 來阻止表單的提交。
這樣確實(shí)比之前好很多:至少在我們修改驗(yàn)證規(guī)則時(shí)顯得毫不費(fèi)力:
validator.add(registerForm.userName,'minLength:2','用戶名不能少于2位')
但是問題也就隨之而來了:我們把對(duì)于用戶名的驗(yàn)證規(guī)則“不能為空”改為了“不能少于兩位”,那么就不能驗(yàn)證“是否為空”了。
能不能像element-ui一樣可以自定義多種驗(yàn)證規(guī)則 呢?就像這樣:
validator.add(registerForm.userName,[{ strategy:'isNoneEmpty', errorMsg:'用戶名不能為空' },{ strategy:'minLength:2', errorMsg:'用戶名長度不能少于2位' }])
現(xiàn)在“rule”是數(shù)組-對(duì)象的形式了,我們需要把add函數(shù)改一下:
Validator.prototype.add=function(dom,rules){ var self=this; for(var i=0,rule;rule=rules[i++];){ (function(rule){ var strategyAry=rule.strategy.split(':'); var errorMsg=rule.errorMsg; self.cache.push(function(){ var strategy=strategyAry.shift(); strategyAry.unshift(dom.value); return strategies[strategy].apply(dom,strategyAry); }); })(rule) } }
策略模式的優(yōu)點(diǎn):
利用組合、委托、多態(tài)等技術(shù)和思想,可以有效地避免多重條件選擇語句(關(guān)于這一點(diǎn),筆者在 這篇文章 中做了詳細(xì)說明);完美實(shí)現(xiàn)了設(shè)計(jì)模式都應(yīng)該具有的“對(duì)外開放-封閉”原則,基于策略模式實(shí)現(xiàn)的規(guī)則大多易于擴(kuò)展、易于使用避免了大量CV的工作
到此這篇關(guān)于從表單校驗(yàn)看JavaScript策略模式的使用詳解的文章就介紹到這了,更多相關(guān)JavaScript策略模式使用內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
JavaScript獲取GridView中用戶點(diǎn)擊控件的行號(hào),列號(hào)
GridView中的某幾列有按鈕,需要獲取用戶當(dāng)前點(diǎn)的按鈕的行號(hào)(捎帶的得到列號(hào))2009-04-04JavaScript如何實(shí)現(xiàn)圖片懶加載(lazyload) 提高用戶體驗(yàn)(增強(qiáng)版)
這篇文章主要介紹了JavaScript如何實(shí)現(xiàn)圖片懶加載(lazyload) 提高用戶體驗(yàn)(增強(qiáng)版)的相關(guān)資料,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下2016-11-11JS中字符串切割為數(shù)組/數(shù)組拼接為字符串的代碼例子
這篇文章主要給大家介紹了關(guān)于JS中字符串切割為數(shù)組/數(shù)組拼接為字符串的相關(guān)資料,數(shù)組是JavaScript中最強(qiáng)大的數(shù)據(jù)結(jié)構(gòu),我們常常通過將字符串轉(zhuǎn)換為數(shù)組來解決許多算法,需要的朋友可以參考下2023-09-09javascript判斷css3動(dòng)畫結(jié)束 css3動(dòng)畫結(jié)束的回調(diào)函數(shù)
本文主要給大家介紹的是如何使用javascript判斷CSS3動(dòng)畫效果結(jié)束,主要是使用了javascript的回調(diào)函數(shù),其思路是一旦動(dòng)畫或變換結(jié)束,回調(diào)函數(shù)就會(huì)觸發(fā)。不再需要大型類庫支持,非常的簡單實(shí)用,推薦給大家。2015-03-03js利用clipboardData實(shí)現(xiàn)截屏粘貼功能
這篇文章主要為大家詳細(xì)介紹了js利用clipboardData實(shí)現(xiàn)截屏粘貼功能,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-10-10