Avoid double click 防止使用者雙擊按鍵
防呆機制對於功能來說是不可缺少的,若少做了往往會造成系統問題(品質),
例如:有的功能因為較花資源,或因系統資源不足回應時間較慢,
使用者就會不斷地去點擊按鍵,誤以為這樣會比較快得到回應,
往往卻讓系統掛點的更快,甚至會有double pay … 嚴重的交易異常,
第一步可以先做的就是防止使用者double click,
在網路上有些解決,本文中做匯整,以便日後查找。
(一)一些基本觀念:
1. 頁面只有Button時, 產生的html 只有submit
2. Button 加入OnClientClick屬性, 產生的html 多了 onclick 事件的程式
Tip: onclick 即是一個function, 若你寫成 OnClientClick=”return false; this.value=1;”後面那段code 永遠都呼叫不到 …
3. 頁面加入Validator 後, 會有驚人多的Code, 很難一言以蔽之, 我們就不探究了,
簡單的說 onclick 事件中多了呼叫WebForm_DoPostBackWithOptions() ,
(下面Code仔細看是有問題的喔)
Tip: OnClientClick 的 return 程式碼會造成Validator失效 !!
此外在form 也多了onsubmit事件並呼叫WebForm_OnSubmit();
如果有興趣, 可以用 IE8 或 Firefox 追蹤, 我簡單的捉出幾個重點, 繪成循序圖, 方便大家來看
由上圖 你可以發現實際執行驗證的程式碼是在 WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions( … )) 中
而 ValidatorOnSubmit 是依照其結果來中斷Postback的動作.
所以當你在OnClientClick加 return 時會造成沒有去做執行驗證, 故ValidatorOnSubmit亦不會幫你block postback.
(二)解決方案
一. Postback 且無Validator
因為直接讓button 的disabled , 會造成頁面中斷Postback , 所以要加一個強迫送出的程式碼
環境:.NET Framework 2.0 (ok)
C# Code 如下:
二. Postback 且有Validator
原本:“Avoid double click” > “驗證成功”> ”Postback”(當驗證失敗時,按鍵亦無法恢復)
改成:“驗證成功” > “Avoid double click” > “Postback”
因要改變其呼叫流程, 故先引用 Page_ClientValidate(), 然後 Button.disabled , 最後再強迫送出程式碼.
參考:ta4ka
環境:.NET Framework 2.0 (ok)
C# Code 如下:
{
System.Text.StringBuilder sbValid = new System.Text.StringBuilder();
sbValid.Append("if (typeof(Page_ClientValidate) == 'function') { ");
sbValid.Append("if (Page_ClientValidate() == false) { return false; }} ");
sbValid.Append("this.value = 'Please wait...';");
sbValid.Append("this.disabled = true;");
sbValid.Append(this.Page.ClientScript.GetPostBackEventReference(button, ""));
sbValid.Append(";");
button.Attributes.Add("onclick", sbValid.ToString());
}
實際產生的JavaScript Code 如下:
if (Page_ClientValidate() == false) { return false; }
}
this.value = 'Please wait...';
this.disabled = true;
__doPostBack('btnOk','');
說穿了就是把 function WebForm_DoPostBackWithOptions() 重組
以上的sample 其實是不完整, 因為如果你附加了WebForm_PostBackOptions 的 actionUrl, trackFocus, clientSubmit 屬性
將會無法處理到, 到時要再多加以下這整段Code來處理
if ((typeof(options.actionUrl) != "undefined") && (options.actionUrl != null) && (options.actionUrl.length > 0)) {
theForm.action = options.actionUrl;
}
if (options.trackFocus) {
var lastFocus = theForm.elements["__LASTFOCUS"];
if ((typeof(lastFocus) != "undefined") && (lastFocus != null)) {
if (typeof(document.activeElement) == "undefined") {
lastFocus.value = options.eventTarget;
}
else {
var active = document.activeElement;
if ((typeof(active) != "undefined") && (active != null)) {
if ((typeof(active.id) != "undefined") && (active.id != null) && (active.id.length > 0)) {
lastFocus.value = active.id;
}
else if (typeof(active.name) != "undefined") {
lastFocus.value = active.name;
}
}
}
}
}
}
if (options.clientSubmit) {
__doPostBack(options.eventTarget, options.eventArgument);
}