有個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.

Post a comment