EasyUI `dialog` 中的確認按鈕 ``,每次開啟對話框後點擊,請求發送次數遞增:第 1 次發 1 請,第 2 次發 2 請,第 3 次發 3 請...
代碼結構導致重複綁定:
// 每次呼叫 chongzhi_shenqing(index) 開啟 dialog 時
$('#div_chongzhi_shenqing').dialog('open'); // dialog 內容已存在 DOM
// 但綁定事件的代碼在 $(function(){ ... }) 中,頁面載入時執行一次
// 問題:若 chongzhi_shenqing 內部有動態載入內容、或 dialog 重新渲染
// 會導致 $('#queren_chongzhi_shenqing').click(...) 重複執行
實際上,EasyUI `dialog` 預設 `closed: true` 時內容已在 DOM,`open` 只是顯示。但若內容是 `href` 載入、或手動 `$(...).html(...)` 重設內容,則每次開啟都會重新綁定。
| 方案 | 代碼 | 優點 | 缺點 |
|---|---|---|---|
| unbind 再綁定(快速修復) | $('#queren_chongzhi_shenqing').off('click').on('click', fn) | 簡單、立即生效 | 治標不治本、若多處綁定需多處修 |
| 事件委派(推薦) | $(document).on('click', '#queren_chongzhi_shenqing', fn) | 動態新增元素自動生效、只綁一次 | 需注意事件冒泡、效能極高頻需優化 |
| 標記旗標防重複 | if(!btn.data('bound')){ btn.on(...).data('bound',true) } | 邏輯清晰 | 需管理旗標生命週期 |
| 模組化封裝(最佳) | 將 dialog 初始化、事件綁定封裝為函數/類,確保僅執行一次 | 架構清晰、可測試、可復用 | 需重構既有代碼 |
// 全域唯一綁定,放在 $(function(){}) 最外層
$(document).on('click', '#queren_chongzhi_shenqing', function() {
var selected = $('#mingxi').datagrid('getSelected');
if (!selected) { alert('請先選擇記錄'); return; }
$.ajax({
url: 'chongzhi.ashx',
type: 'post',
data: {
'id': selected.ID,
'Money': $('#chongzhi_money_shenqing').val(),
'user': selected.UserName
},
success: function(msg) {
var tips = {'ok':'充值成功','null':'無記錄請刷新','error':'充值失敗','small':'金額不能小於0'};
alert(tips[msg] || '未知回應');
if (msg === 'ok') {
$('#mingxi').datagrid('reload');
$('#div_chongzhi_shenqing').dialog('close');
$('#chongzhi_money_shenqing').val('');
}
},
error: function() { alert('網路錯誤'); }
});
});
// 開啟 dialog 時只需設定 selected,不再綁定事件
function chongzhi_shenqing(index) {
$('#mingxi').datagrid('selectRow', index);
// selected 由全域或閉包變數持有,或從 datagrid 取得
$('#div_chongzhi_shenqing').dialog('open');
}
重複觸發本質是同一事件處理器被重複附加。根治:事件委派 + 單一綁定點。EasyUI 專案中,優先使用框架內建 `toolbar`/`onOpen` 生命週期管理事件,避免手動 `$().click()`/`on()` 散落各處。