[js]jQuery EasyUI的linkbutton組件disable方法無法禁用jQuery綁定事件的問題分析
問題由來
linkbutton 是 jQuery EasyUI 中常用的一個控件,可以使用它創建按鈕。用法很簡單,使用 a 標簽給一個easyui-linkbutton 的class就可以了。
<a id="btn" class="easyui-linkbutton">這是一個按鈕</a>
或者使用代碼方式。
$("#btn").linkbutton();
實際使用時,經常會使用 jQuery 添加事件處理函數。例如
$("#btn").click(function () { alert("點擊事件"); });
在使用過程中可能會需要暫時禁用這個按鈕,easyui 已經提供了禁用按鈕的方法 disable,使用方法也很簡單
$(function(){ $("#btn").linkbutton(“disable”); })
到這兒問題就來了,再點擊一下,提示框照依然彈了出來,disable方法好像並沒有什麽效果
原因分析:不同的事件處理方式
在 DOM 中,存在著兩類不同的事件處理方式,DOM0式和 DOM2 方式。
DOM0通過在HTML中設置屬性,或者在JavaScript中設置一個對象的屬性(property)的方法註冊事件. 例如
varbtn = document.getElementById("btn"); btn.onclick = function () { alert("clicked"); };
取消事件註冊,將 onclick 賦予為null 即可
btn.onclick = null;
DOM 2通過addEventListener()方法註冊事件
var btn = document.getElementById("btn"); btn.addEventListener("click", function () { alert("clicked"); },false);
通過addEventListener添加的事件只能處理程序只能使用removeEventListener來移除,移除時傳入的參數與添加處理程序時使用的參數相同,這也意味著通過addEventListener添加的匿名函數將無法移除
問題在於,這兩種方式是各自獨立處理的,互相並不影響。
由於 easyui 中使用了 DOM0 方式處理按鈕的啟用和禁用,而 jQuery 則使用 DOM2 方式進行事件的註冊,所以之前的禁用失效了。
使用 DOM Level 0 方式,我們可以通過事件名稱,方便地取得原來註冊的事件處理函數,保存起來,以便以後回復。這正是 linkbutton 現在已經完成的。
解決方法:修復 linkbutton 的啟用和禁用
修改的方式就是在原來的基礎上,增加對於通過 DOM Level 2 方式註冊的事件進行處理。檢查是否註冊了 jQuery 的 click 事件處理函數,如果有,在數據緩存對象上增加一個名為 savedHandlers 的數組來保存原來的點擊事件處理函數,然後,從原來的對象上取消已經註冊的事件處理函數。恢復的時候,檢查數據對象上是否有保存的事件處理函數數組,如果存在,遍歷這個數組,將這些事件處理函數重新註冊到元素上。
function setButtonState(domElem, disabled) { // 設置按鈕狀態 var data = $.data(domElem, "linkbutton"); // 獲取對象的數據 if (disabled) { // 禁用按鈕 data.options.disabled = true; var href = $(domElem).attr("href"); // 獲取超級連接 if (href) { data.href = href; // 保存原來的超級鏈接 $(domElem).attr("href", "javascript:void(0)"); // 重新設置 } if (domElem.onclick) { // 是否有點擊事件處理 data.onclick = domElem.onclick; domElem.onclick = null; // 取消掉 } var eventData = $(domElem).data("events") || $._data(domElem, ‘events‘); if (eventData && eventData["click"]) { var clickHandlerObjects = eventData["click"]; data.savedHandlers = []; for (var i = 0; i < clickHandlerObjects.length; i++) { if (clickHandlerObjects[i].namespace != "menu") { var handler = clickHandlerObjects[i]["handler"]; $(domElem).unbind(‘click‘, handler); data.savedHandlers.push(handler); } } } $(domElem).addClass("l-btn-disabled"); // 使用樣式 } else { data.options.disabled = false; // 啟用按鈕 if (data.href) { // 恢復原來的超級鏈接 $(domElem).attr("href", data.href); } if (data.onclick) { // 恢復原來的點擊事件處理 domElem.onclick = data.onclick; } if (data.savedHandlers) { for (var i = 0; i < data.savedHandlers.length; i++) { $(domElem).click(data.savedHandlers[i]); } } $(domElem).removeClass("l-btn-disabled"); } }
如果不想修改easyui的源代碼,可以使用擴展方法來解決這個問題
/** * linkbutton方法擴展 * @param {Object} jq */ $.extend($.fn.linkbutton.methods, { /** * 激活選項(覆蓋重寫) * @param {Object} jq */ enable: function(jq){ return jq.each(function(){ var state = $.data(this, ‘linkbutton‘); if ($(this).hasClass(‘l-btn-disabled‘)) { var itemData = state._eventsStore; //恢復超鏈接 if (itemData.href) { $(this).attr("href", itemData.href); } //回復點擊事件 if (itemData.onclicks) { for (var j = 0; j < itemData.onclicks.length; j++) { $(this).bind(‘click‘, itemData.onclicks[j]); } } //設置target為null,清空存儲的事件處理程序 itemData.target = null; itemData.onclicks = []; $(this).removeClass(‘l-btn-disabled‘); } }); }, /** * 禁用選項(覆蓋重寫) * @param {Object} jq */ disable: function(jq){ return jq.each(function(){ var state = $.data(this, ‘linkbutton‘); if (!state._eventsStore) state._eventsStore = {}; if (!$(this).hasClass(‘l-btn-disabled‘)) { var eventsStore = {}; eventsStore.target = this; eventsStore.onclicks = []; //處理超鏈接 var strHref = $(this).attr("href"); if (strHref) { eventsStore.href = strHref; $(this).attr("href", "javascript:void(0)"); } //處理直接耦合綁定到onclick屬性上的事件 var onclickStr = $(this).attr("onclick"); if (onclickStr && onclickStr != "") { eventsStore.onclicks[eventsStore.onclicks.length] = new Function(onclickStr); $(this).attr("onclick", ""); } //處理使用jquery綁定的事件 var eventDatas = $(this).data("events") || $._data(this, ‘events‘); if (eventDatas["click"]) { var eventData = eventDatas["click"]; for (var i = 0; i < eventData.length; i++) { if (eventData[i].namespace != "menu") { eventsStore.onclicks[eventsStore.onclicks.length] = eventData[i]["handler"]; $(this).unbind(‘click‘, eventData[i]["handler"]); i--; } } } state._eventsStore = eventsStore; $(this).addClass(‘l-btn-disabled‘); } }); } });
[js]jQuery EasyUI的linkbutton組件disable方法無法禁用jQuery綁定事件的問題分析