<asp:Button ID="btnSubmit" runat="server"
UseSubmitBehavior="false"
OnClientClick="this.disabled = true; this.value = '處理中...';"
Text="送出" OnClick="btnSubmit_Click" />
type="submit",改為 type="button" + __doPostBack,讓我們完全掌控客戶端行為。protected void btnSubmit_Click(object sender, EventArgs e)
{
if (!Page.IsValid) return; // 驗證失敗
// 業務邏輯...
bool success = DoBusinessLogic();
if (success)
{
// 成功:頁面會重整或導向,按鈕自然恢復
}
else
{
// 失敗:重新啟用按鈕並提示
string script = $@"document.getElementById('{btnSubmit.ClientID}').disabled = false;
document.getElementById('{btnSubmit.ClientID}').value = '重新送出';";
ScriptManager.RegisterStartupScript(this, GetType(), "reEnableBtn", script, true);
}
}
<asp:UpdatePanel ID="upMain" runat="server" UpdateMode="Conditional">
<ContentTemplate>
<asp:Button ID="btnSubmit" runat="server"
UseSubmitBehavior="false"
OnClientClick="disableBtn(this);"
Text="送出" OnClick="btnSubmit_Click" />
<asp:Label ID="lblMsg" runat="server" />
</ContentTemplate>
<Triggers>
<asp:AsyncPostBackTrigger ControlID="btnSubmit" EventName="Click" />
</Triggers>
</asp:UpdatePanel>
<script>
function disableBtn(btn) {
btn.disabled = true;
btn.value = '處理中...';
}
function enableBtn(btn, text) {
btn.disabled = false;
btn.value = text || '送出';
}
</script>
protected void btnSubmit_Click(object sender, EventArgs e)
{
try
{
// 業務邏輯
bool ok = DoWork();
lblMsg.Text = ok ? "成功" : "失敗:原因...";
}
catch (Exception ex)
{
lblMsg.Text = "錯誤:" + ex.Message;
}
finally
{
// 部分更新完成後,按鈕仍處於 disabled 狀態,需 JS 恢復
string script = $"enableBtn(document.getElementById('{btnSubmit.ClientID}'), '送出');";
ScriptManager.RegisterStartupScript(this, GetType(), "reEn", script, true);
}
}
<button id="btnSubmit" type="button" class="btn-primary">送出</button>
<script>
$('#btnSubmit').on('click', function () {
var $btn = $(this).prop('disabled', true).text('處理中...');
$.post('Handler.ashx', { action: 'submit', data: collectForm() })
.done(function (res) {
if (res.success) location.href = res.redirectUrl;
else alert(res.message);
})
.fail(function () { alert('網路錯誤'); })
.always(function () { $btn.prop('disabled', false).text('送出'); });
});
</script>
| 方案 | 適用場景 | 優點 | 缺點 |
|---|---|---|---|
| 核心屬性法 | 簡單表單、全頁 PostBack | 零 JS 邏輯、無維護成本 | 驗證失敗時按鈕已恢復,無法保持禁用 |
| RegisterStartupScript | 傳統 WebForms、需後端控制 | 伺服器端決定是否恢復 | 全頁重整閃爍 |
| UpdatePanel | 局部更新、保留 ViewState | 無閃爍、程式碼結構熟悉 | ViewState 傳輸量大、難除錯 |
| 前端 AJAX | 現代化、API 分離、SPA 傾向 | 體驗最佳、前後端分離、可複用 API | 需自行處理防偽、驗證、狀態管理 |
<%@ Page ... %>
<asp:HiddenField ID="hfToken" runat="server" />
// Page_Load
if (!IsPostBack) hfToken.Value = Guid.NewGuid().ToString();
// 伺服器端驗證
if (hfToken.Value != Session["FormToken"]?.ToString()) throw new InvalidOperationException("CSRF 攻擊");
// 業務完成後
Session["FormToken"] = Guid.NewGuid().ToString(); // 換新 Token
配合 UseSubmitBehavior="false" 可有效防止重放攻擊與重複提交。