預(yù)覽
作為一名前端人士,在一個web項目中七芭,注冊、登錄蔑赘、修改用戶信息等功能的實現(xiàn)都離不開表單狸驳。在將用戶輸入的數(shù)據(jù)提交給后臺之前,常常需要做一些客戶端力所能及的校驗工作缩赛。比如注冊的時候需要校驗是否填寫了用戶名耙箍,密碼的長度是否符合規(guī)定,等等酥馍。好了究西,您可能會說,說出你的夢想物喷,開始你的表演卤材,接下來我要開始我的表演了。??
假設(shè)現(xiàn)在我要寫一個注冊頁面峦失,在店家注冊按鈕之前扇丛,有如下幾條校驗邏輯:
用戶名不能為空
密碼長度不能小于6位
手機(jī)號碼必須符合格式
一、表單校驗的第一個版本
<html>
<body>
<form action="https://www.baidu.com" method="post" id="registerForm">
請輸入用戶名<input type="text" name="userName"><br>
請輸入密碼 <input type="password" name="password"><br>
請輸入手機(jī)號碼<input type="text" name="phoneNumber"><br>
<button>提交</button>
</form>
</body>
</html>
么有寫CSS樣式尉辑,感覺界面丑哭??帆精,實現(xiàn)功能最重要,對不?
<script>
const registerForm = document.getElementById('registerForm');
registerForm.onsubmit = function() {
if (registerForm.userName != "") {
if (registerForm.password.length >= 6) {
if (/^1[3|4|5|7|8][0-9]{9}$/.test(registerForm.phoneNumber)) {
alert('成功');
} else {
alert('請輸入正確的的手機(jī)號卓练!');
return false;
}
} else {
alert('密碼不能小于六位');
return false;
}
} else {
alert("用戶名不能為空隘蝎!");
return false;
}
}
</script>
這是一種最常見的代碼編寫方式,但是他的缺點顯而易見襟企。registerForm.onsubmit函數(shù)比較龐大嘱么,包含了過多的if-else語句,如果增加一條新的校驗規(guī)則顽悼,或者想把免得長度校驗從6位增加到8位曼振,要去registerForm.onsubmit內(nèi)部更改,這樣就違反了開放-封閉的原則蔚龙。
二冰评、用策略模式實現(xiàn)表單的校驗
我們經(jīng)常說,條條大路通羅馬木羹,在現(xiàn)實生活中甲雅,很多時候也有很多途徑到達(dá)同一個目的地。假如我們要去某個地方旅游坑填,我們可以這樣選擇:
不考慮金錢的情況下抛人,為了節(jié)省時間,我們選擇乘坐飛機(jī)
考慮錢的話穷遂,那就火車或者bus
像我這樣的只能來個自行車去旅游了,這就是差距啊??娱据,到此為止蚪黑,我們來說說主角吧,蹬蹬蹬蹬中剩,策略模式來了忌穿。
策略模式就是定義一系列算法,把它們一個個封裝起來结啼,并且是它們可以相互替換掠剑。
用策略模式來實現(xiàn)表單的檢驗,第一步我們先來把這些校驗邏輯封裝成策略對象
var strategies = {
// errorMsg參數(shù)郊愧,提升了適用性
isNonEmpty: function(value, errorMsg) { //不為空
if (value === '') {
// 返回字符串true 錯誤信息
return errorMsg;
}
},
minLength: function(value, length, errorMsg) { //限制最小長度
if (value.length < length) {
return errorMsg;
}
},
isMobile: function(value, errorMsg) {
if (!/^1[1|5|8|7|4|3][0-9]{9}$/.test(value)) { //電話號碼校驗
return errorMsg;
}
}
}
接下來就是實現(xiàn)Validator類了朴译。Validator負(fù)責(zé)接收用戶的請求并委托給strategy對象。我們先來了解下用戶是如何向Validator類發(fā)送請求的属铁,這有助于我們知道如何去編寫Validator類的代碼眠寿。代碼如下:
function validateFunc() {
// 校驗處理 分離出去
var validator = new Validator(); //創(chuàng)建validator對象
// 一個個去校驗
// 數(shù)組 遍歷
/**********************添加校驗規(guī)則**********************/
validator.add(registerForm.userName, 'isNonEmpty', '用戶名不能為空');
validator.add(registerForm.password, 'minLength:6', '密碼長度不能少于6位');
validator.add(registerForm.phoneNumber, 'isMobile', '手機(jī)號碼格式不正確')
var errorMsg = validator.start(); //獲取校驗結(jié)果
// 一個個去校驗
return errorMsg; //返回校驗結(jié)果
}
registerForm.onsubmit = function() {
// 一票規(guī)則 數(shù)組
var errorMsg = validateFunc(); //如果errorMsg有確切的返回值,說明校驗未通過焦蘑,即輸入的內(nèi)容不符合規(guī)則
if (errorMsg) {
alert(errorMsg);
return false; //阻止表單提交
}
}
通過這段代碼盯拱,我們先創(chuàng)建了一個validator對象,然后通過validator.add方法,往validator對象中添加一些檢驗規(guī)則狡逢。validator.add方法接受三個參數(shù)宁舰,
validator.add(registerForm.password, 'minLength:6', '密碼長度不能少于6位');
registerForm.password為參與校驗的input輸入框。
'minLength:6'是一個以冒號隔開的字符串奢浑。冒號前面的minLength代表挑選的strategy對象蛮艰,冒號后面的數(shù)字6表示在校驗中過程中所必須的參數(shù)。'minLength:6'的意思是校驗registerForm.password這個文本框輸入的最小長度不能小于6殷费。如果這個字符串中不過不包含冒號印荔,說明教研過程中不需要額外的參數(shù),如'isNonEmpty'&'isMobile'详羡。
第三個參數(shù)是當(dāng)被校驗的值不符合規(guī)則的時仍律,返回的錯誤信息。
在往validator對象里添加了一系列的校驗規(guī)則后实柠,我們就要使用validator.start()方法來啟動校驗水泉。如果validator.start()返回一個確切的errorMsg字符串當(dāng)作返回值,就表明校驗沒有通過窒盐,此時需要registerForm.onsubmit方法返回false來阻止表單的提交草则。
最后實現(xiàn)Validator類:
var Validator = function() {
this.cache = [];
}
Validator.prototype.add = function(ele, rule, errorMsg) {
var arr = rule.split(':');
this.cache.push(function() {
// 規(guī)則
var strategy = arr.shift();
arr.unshift(ele.value);
arr.push(errorMsg);
return strategies[strategy].apply(ele, arr);
});
}
Validator.prototype.start = function() {
for (var i = 0, validatorFunc; validatorFunc = this.cache[i++];) {
var msg = validatorFunc();
if (msg) {
return msg;
}
}
};
使用策略模式重構(gòu)代碼后,僅僅可以通過“配置”的方式就可以完成一個表單的校驗蟹漓,這些校驗規(guī)則也可以復(fù)用在程序的任何地方炕横,這就是我們所所得,處處適用葡粒。
在修改某個校驗規(guī)則的時候份殿,只需要編寫或者改寫少量的代碼。假如想將用戶名輸入框的校驗規(guī)則修改成用戶名不能少于四個字符嗽交。代碼如下所示:
validator.add(registerForm.userName, 'isNonEmpty', '用戶名不能為空');
//改成
validator.add(registerForm.userName, 'minLength:8', '用戶名長度不能小于8位');
學(xué)習(xí)中遇到的問題
(1)什么鬼卿嘲?在校驗失敗的情況下,還會實現(xiàn)頁面的跳轉(zhuǎn)夫壁,真的讓人有點受不了拾枣,所以我要說的是,一定要在registerForm.onsubmit方法返回false來阻止表單的提交盒让。
(2)再來解釋下手機(jī)號碼的校驗規(guī)則
isMobile: function(value, errorMsg) {
if (!/^1[1|3|4|5|7|8][0-9]{9}$/.test(value)) { //電話號碼校驗
return errorMsg;
}
}
表示第一位只匹配數(shù)字1梅肤,第二位匹配(3|4|5|7|8)里面的任意一個數(shù)值,剩下的9位是沒有限制的邑茄,也就是可以匹配0-9之間的任意數(shù)字凭语,最后以$結(jié)尾。test函數(shù)返回的是一個boolean值撩扒。正則表達(dá)式中 test似扔、exec吨些、match 方法區(qū)別http://www.cnblogs.com/meixianfeng/articles/2762273.html。
代碼地址:https://github.com/SiHao24/js_pattern
結(jié)語
策略模式的巧妙之處遠(yuǎn)遠(yuǎn)不止這些炒辉,我只是列舉了其中小小的一個環(huán)節(jié)豪墅!還需要花費更多的時間去學(xué)習(xí)其中的奧秘。雖然開始學(xué)的很艱難黔寇,但是努力過后偶器,就會陶醉在知識的海洋里!
有建議或者覺得有錯誤的地方可以指出來喲,讓我跟隨大佬們的步伐缝裤,繼續(xù)努力吧屏轰!