從丑陋到優雅,讓代碼越變越美(客戶端檢測方法思考)
大家都知道,客戶端檢測不單可以讓用戶獲得更好的體驗,而且可以通過校驗數據大大減少客戶端和服務器端的往返次數,減少服務器負擔。在這里,小弟打算回顧一下自己在客戶端檢測方面的學習歷程和采用方法,如果大家有什么更好的方法或者建議,歡迎提出來共享!共同進步!
為了方便舉例和說明,先構建一個簡單的html頁面,如下:
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>JS Verify</title>
</head>
<body>
<div>
<span>請輸入用戶名,年齡和自我介紹:</span>
<br />
<span>用戶名:<input type="text" id="txtName" size="20" /></span>
<br />
<span>年齡:<input type="text" id="txtAge" size="5" />歲</span>
<br />
<span>自我介紹:</span>
<br />
<span><textarea id="txtIntro" rows="10" cols="50"></textarea></span>
<br />
<span><input type="button" value="提交信息" /></span>
</div>
</body>
</html>
第一階段是:續項強寫
每個人都基本會經過這個階段,就是對檢測內容每個都手工校驗。很慚愧,自己也寫過不少這樣的代碼。。這個階段的代碼如下:
function SubmitInfo()
{
var name = document.getElementById("txtName");
var age = document.getElementById("txtAge");
var intro = document.getElementById("txtIntro");
if(name == null || name.value == "")
{
alert("請輸入用戶名!");
return false;
}
if(!/^[\u4E00-\u9FA5a-z0-9_]*$/gi.test(name.value))
{
alert("用戶名只能由中文,英文,數字及下劃線組成!");
return false;
}
if(age == null || age.value == "")
{
alert("請輸入年齡!");
return false;
}
if(!/^[1-9]\d$/.test(age.value))
{
alert("年齡必須為正整數!");
return false;
}
if(intro == null || intro.value == "")
{
alert("請輸入自我介紹!");
return false;
}
alert("提交成功!");
return true;
}
不評價這個了。。因為每個人都可能因為寫這些方法檢測邏輯寫得眼冒星星手抽筋的!弄的經常下班了還在撲哧撲哧的寫啊寫。。。。
第二階段:集中消滅
相信不少初學者現在還是處于這個階段,這階段的同學們已經被第一階段折磨怕了。很快就想出了集中消滅相同類型檢測的方法。就是寫檢測函數,如下:
function isEmpty(obj)
{
if(obj == null || obj.value == "")
return false;
return true;
}
function isInt(val)
{
return /^[1-9]\d$/.test(val);
}
function isSafeString(val)
{
return /^[\u4E00-\u9FA5a-z0-9_]*$/gi.test(val);
}
同學們很可能還將上邊代碼獨立成一個公共類,叫Common.js什么的,然后實際檢測引用一下,就容易多了:
function SubmitInfo()
{
var name = document.getElementById("txtName");
var age = document.getElementById("txtAge");
var intro = document.getElementById("txtIntro");
if(!isEmpty(name))
{
alert("請輸入用戶名!");
return false;
}
if(!isSafeString(name.value))
{
alert("用戶名只能由中文,英文,數字及下劃線組成!");
return false;
}
if(!isEmpty(age))
{
alert("請輸入年齡!");
return false;
}
if(!isInt(age.value))
{
alert("年齡必須為正整數!");
return false;
}
if(!isEmpty(intro))
{
alert("請輸入自我介紹!");
return false;
}
alert("提交成功!");
return true;
}
看,不用每次寫那些該死檢測邏輯了。。要檢測什么只要調用一下已經寫好的公共檢測方法就行了。輕松吧?!不過,還能更輕松嗎?當然!請看:
第三階段:鏈式的威力
看著一大堆if else總是心里覺得不舒服,對吧?一串串的又不是羊肉串,雖然不能吃,也要消滅它們!這時候,是Javascript的prototype出場的時候了。通過擴展prototype,可以獲得簡潔優雅的代碼:
function SubmitInfo()
{
var name = document.getElementById("txtName");
var age = document.getElementById("txtAge");
var intro = document.getElementById("txtIntro");
if(!name.value.initVerify().isEmpty("請輸入用戶名!").isSafeString("用戶名只能由中文,英文,數字及下劃線組成!").verifyComplete())
return false;
if(!age.value.initVerify().isEmpty("請輸入年齡!").isInt("年齡必須為正整數!").verifyComplete())
return false;
if(!intro.value.initVerify().isEmpty("請輸入自我介紹!").verifyComplete())
return false;
alert("提交成功!");
return true;
}
很簡潔吧?相對前邊一大串的羊肉串,是不是順眼多了啊?哦,如何實現?其實很簡單:
var validateStatus;
var validateMessage;
String.prototype.initVerify = function()
{
validateStatus = true;
validateMessage = "";
return this;
}
String.prototype.isEmpty = function(msg)
{
if(validateStatus)
{
if(this == null || this == "")
{
validateStatus = false;
validateMessage = msg;
}
}
return this;
}
String.prototype.isInt = function(msg)
{
if(validateStatus)
{
if(!/^[1-9]\d$/.test(this))
{
validateStatus = false;
validateMessage = msg;
}
}
return this;
}
String.prototype.isSafeString = function(msg)
{
if(validateStatus)
{
if(!/^[\u4E00-\u9FA5a-z0-9_]*$/gi.test(this))
{
validateStatus = false;
validateMessage = msg;
}
}
return this;
}
String.prototype.verifyComplete = function()
{
if(!validateStatus)
alert(validateMessage);
return validateStatus;
}
怎么樣?是不是很簡單啊?這個prototype真是一個好東西啊!!鏈式編程,贊!!呵呵,怎么?你還不滿足,代碼太長?人心不足啊。我試試吧。。
第四階段:自定義屬性
這個階段的提交函數如下:
function SubmitInfo()
{
if(!Verify(document.getElementById("txtName"))) return false;
if(!Verify(document.getElementById("txtAge"))) return false;
if(!Verify(document.getElementById("txtIntro"))) return false;
alert("提交成功!");
return true;
}
想不通吧?怎么所有檢測都一樣啊?這不忽悠人嗎?哈哈,要實現這個需要在html代碼加點醬料:
<div>
<span>請輸入用戶名,年齡和自我介紹:</span>
<br />
<span>用戶名:<input type="text" id="txtName" size="20" verifyOptions='{"Empty":{"Flag":false,"Message":"請輸入用戶名!"},"SafeString":{"Message":"用戶名只能由中文,英文,數字及下劃線組成!"}}' /></span>
<br />
<span>年齡:<input type="text" id="txtAge" size="5" verifyOptions='{"Empty":{"Flag":false,"Message":"請輸入年齡!"},"Int":{"Message":"年齡必須為正整數!"}}' />歲</span>
<br />
<span>自我介紹:</span>
<br />
<span><textarea id="txtIntro" rows="10" cols="50" verifyOptions='{"Empty":{"Flag":false,"Message":"請輸入自我介紹!"}}' ></textarea></span>
<br />
<span><input type="button" onclick="return SubmitInfo();" value="提交信息" /></span>
</div>
看到了吧,我們自定義了個叫verifyOption的屬性,就是根據它們實現的分別對待的。就好像每個人都有銀行卡,但是里面的錢都不一樣一樣(這個比喻好像比較牽強^_^)
還是看看Verify函數到底干了什么東西吧:
function Verify(obj)
{
if(obj.attributes["verifyOptions"] == undefined)
{
alert("請定義verifyOptions!")
return false;
}
var options = obj.attributes["verifyOptions"].nodeValue;
if(!options.isEmpty("檢測參數不正確!"))
return false;
options = options.parseJSON();
if(options.Empty != undefined && options.Empty.Flag == false)
{
if(!obj.value.isEmpty(options.Empty.Message))
return false;
}
if(options.Int != undefined)
{
if(!obj.value.isInt(options.Int.Message))
return false;
}
if(options.SafeString != undefined)
{
if(!obj.value.isSafeString(options.SafeString.Message))
return false;
}
return true;
}
就是檢測自定義屬性里面的設置,根據設置來進行相應檢測。這下大家滿足了吧?每次檢測都一律一句Verify(*)就搞掂了!!QA的MM說檢測不對?哦,不用急不用急,修改一下自定義屬性verifyOption就好了。哈哈~~~
第五階段:可配置
怎么還有第五階段?瘋狂了瘋狂了~~(小子去死!!番茄,雞蛋都丟上來了~~)唉,大家要注意文明禮貌嘛,丟著我沒有關系,丟著花花草草也不好嘛。
<div>
<span>請輸入用戶名,年齡和自我介紹:</span>
<br />
<span>用戶名:<input type="text" id="txtName" size="20" /></span>
<br />
<span>年齡:<input type="text" id="txtAge" size="5" />歲</span>
<br />
<span>自我介紹:</span>
<br />
<span><textarea id="txtIntro" rows="10" cols="50"></textarea></span>
<br />
<span><input id="btnSubmit" type="button" value="提交信息" /></span>
</div>
第五階段的html代碼已經回復清爽了,畢竟自定義屬性好像不太友善,不標準!既然不標準就放棄吧!是不是有同學懷疑,這樣檢測函數豈不是要寫更對邏輯,一定比較臃腫吧?好吧,大家看檢測函數:
function SubmitInfo()
{
if(!VerifyComplete())
return false;
alert("提交成功!");
return true;
}
不是吧??騙人的吧?但是,事實如此,第五階段就是這樣簡潔,這樣優雅的實現了和上邊幾個階段同樣的功能。不相信,那就來看看吧!不過,第五階段為了方便,引用了JQuery,找東西,它的搜索器還真好用。
這個階段我們的檢測配置都寫到一個變量里面了:
var verifyConfig = [
{"Id":"txtName", "Option":{"Empty":{"Flag":false,"Message":"請輸入用戶名!"},"SafeString":{"Message":"用戶名只能由中文,英文,數字及下劃線組成!"}}},
{"Id":"txtAge", "Option":{"Empty":{"Flag":false,"Message":"請輸入年齡!"},"Int":{"Message":"年齡必須為正整數!"}}},
{"Id":"txtIntro", "Option":{"Empty":{"Flag":false,"Message":"請輸入自我介紹!"}}}];
這個變量我叫配置變量,建議大家將這些變量都放到同一個文件,叫verifyConfig.js?反正我是這么叫的,要修改檢測邏輯,就修改這個配置文件就好了,當然,例子由于要強調第五階段的簡潔,就將VerifyComplete()函數參數設置為空,其實它應該有一個參數,用來傳入設置變量。這樣才通用。
最后奉上VerifyComplete()函數:
function VerifyComplete()
{
var controls = $(":input");
var verifyFlag = true;
$.each(controls, function(i, n) {
if(verifyFlag)
verifyFlag = Verify(n);
});
return verifyFlag;
}
function Verify(obj)
{
var options;
$.each(verifyConfig, function(i, n) {
if(n.Id == obj.id)
options = n.Option;
});
if(options == undefined)
return true;
if(options.Empty != undefined && options.Empty.Flag == false)
{
if(!obj.value.isEmpty(options.Empty.Message))
return false;
}
if(options.Int != undefined)
{
if(!obj.value.isInt(options.Int.Message))
return false;
}
if(options.SafeString != undefined)
{
if(!obj.value.isSafeString(options.SafeString.Message))
return false;
}
return true;
}
斗膽第一次上首頁,希望能得到大家指點,進入第六階段。第六階段是怎么樣?我還真想不到!
附上上述完整代碼:點擊下載
再次瀏覽自己的代碼,發現很多類似:
if(xxx)
return true;
else
return false;
上邊的代碼是很笨蛋的.直接一句:
return xxx;
或者
return !xxx;
就好了..何必大費周章呢.汗死了...自己撞一下墻再反思...哦,還有類似:
if(xxx == true)

也是很笨蛋的,只要xxx是bool值.就直接:
if(xxx)

好了...罰自己面壁思過!
浙公網安備 33010602011771號