跨瀏覽器筆記-Submit鈕Click事件設定disabled的行為差異
8 |
有個ASP.NET WebForm網頁,因PostBack後的處理邏輯頗為耗時,為防止使用者不耐久侯重複按下送出鈕(那種一急起來會把網頁當快打旋風,瘋狂按鈕連發的使用者,大家都有遇過吧?),加了幾行簡單的jQuery,在送出鈕的Click事件裡設定disabled屬性停用按鈕,再順便顯示"處理中,請稍侯..."請使用者稍安勿躁。其運作如以下範例所示: (PostBack時利用Thread.Sleep 3秒模擬長時間執行)
<%@ Page Language="C#" %>
<!DOCTYPE html>
<script runat="server">
void Page_Load(object sender, EventArgs e)
{
if (IsPostBack)
{
System.Threading.Thread.Sleep(3000);
Response.Write("PostBack!");
Response.End();
}
}
</script>
<html>
<head runat="server">
<title></title>
<script src="http://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.7.2.js"></script>
<script>
$(function () {
$("#btnSend").click(function () {
$("#lblMsg").text("處理中,請稍候...");
$(this).prop("disabled", true);
});
});
</script>
</head>
<body>
<form id="form1" runat="server">
<input type="submit" id="btnSend" value="Send" />
<span id="lblMsg"></span>
</form>
</body>
</html>
用IE9測得很開心後交付程式,使用者測試時卻回報按鈕後網頁一直顯示處理中,久久無動靜。經對照測試環境並觀察網路封包,這才發現此寫法在IE7/8(或IE9開相容模式時)會因Submit鈕被disabled而取消Post表單的行為,換句話說,HTML表單永遠不會被傳送到後端。
另外再測試了Chrome及Firefox,很有趣,Chrome跟IE8一樣會因此取消 送出,Firefox則跟IE9一樣可以正常運作。(IE9表示: 謝謝你,Firefox,不然我又要被大噹特噹了~)
無論如何,這個跨瀏覽器問題還是要解決,祭出setTimeout大法,將設定disabled的時機延到Click事件完成後,問題就排除囉~
<script>
$(function () {
$("#btnSend").click(function () {
var $btn = $("#btnSend");
setTimeout(function () {
$btn.prop("disabled", true);
$("#lblMsg").text("處理中,請稍候...");
}, 10);
});
});
</script>
[2012-06-29更新]感謝網友Jax及佑翔的回饋,提出可以在onclick中直接觸發.submit()以及改在onsubmit事件中停用按鈕的建議,實務應用上會比原本的做法更簡潔周詳,故可重新調整寫法如下:
$(function () {
$("#form1").submit(function() {
$("#lblMsg").text("處理中,請稍候...");
$("#btnSend").prop("disabled", true);
});
});
Comments
# by 胡忠晞
用到 setTimeout 會不會太複雜了!簡單的將表單送出不就好了! $(this).prop("disabled", true); $(this).closest('form').submit(); //or $('#form1').submit();
# by Jeffrey
to Jax, 原本直覺的想法是從"onclick事件完成"到"表單真正.submit()之前",還存在被插入其他程式邏輯的空間,不想在onclick中直接呼叫form.submit()是怕破壞原有的執行順序。 不過想想,在絕大多數的情境下這層顧慮是多餘的,同意您的意見,在onclick中直接呼叫.submit()更簡單。
# by 佑翔
親愛的黑大~ 關於這點我提供一點小小的看法 form的submit不一定是某個submit按鈕造成的 如果焦點停留在form的某個input上 直接按下enter也會造成form submit 以時間點來看,在"submit前"做可能才是最正確的 所以,一般我都會這樣做 $(function () { $("#form1").submit(function (e) { $("#lblMsg").text("處理中,請稍候..."); $("#btnSend").prop("disabled", true); }); });
# by Jeffrey
to 佑翔,謝謝補充,同一邏輯掛在submit事件確實更周延,已經將你的建議納入本文。
# by 胡忠晞
這種常用的功能,我會將它定義成延伸屬性,這樣其他要用到的時候就會很快樂。 <form id="form_1" submitOneOnly="1"></form> <script type="text/javascript"> /*放在 onLoad 可以確保是最後一個註冊的 submit 事件 */ $(window).load(function(){ $("form[submitOneOnly]").submit(function(){ if($(this).prop('submit_flag')){ return false; } $(this).prop("submit_flag",true); }); }); </script> <script type="text/javascript"> jQuery(function($) { $("#form_1").submit(function(){ /*其他輸入檢查,只要 return false; 就會結束送出,而 submitOneOnly 的事件就不會觸發。*/ }); }); </script>
# by 胡忠晞
[什麼我的 tab 都不見了!一定要龜毛一下,上一篇幫我刪除。] 這種常用的功能,我會將它定義成延伸屬性,這樣其他要用到的時候就會很快樂。 <form id="form_1" submitOneOnly="1"></form> <script type="text/javascript"> /*放在 onLoad 可以確保是最後一個註冊的 submit 事件 */ $(window).load(function(){ $("form[submitOneOnly]").submit(function(){ if($(this).prop('submit_flag')){ return false; } $(this).prop("submit_flag",true); }); }); </script> <script type="text/javascript"> jQuery(function($) { $("#form_1").submit(function(){ /*其他輸入檢查,只要 return false; 就會結束送出,而 submitOneOnly 的事件就不會觸發。*/ }); }); </script>
# by Jeffrey
to Jax, 謝謝補充!! 留言TextArea中的Tab在存檔時會被忽略,Sorry。 我喜歡你的龜毛,上篇決定幫你留著,更能突顯"專注完美,近乎苛求"~~ :P
# by noroi
如果你的表單有用到asp.net的欄位驗證例如 RequiredFieldValidator 之類的, 你寫的方法會失效. 最好要加一下Page_ClientValidate的檢查.有過才disable button.