1. 程式人生 > >[js]jQuery EasyUI的linkbutton組件disable方法無法禁用jQuery綁定事件的問題分析

[js]jQuery EasyUI的linkbutton組件disable方法無法禁用jQuery綁定事件的問題分析

eth easyu 通過 end 正是 new 數據 html 事件

問題由來

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)的方法註冊事件. 例如

var
btn = 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綁定事件的問題分析