问题由来
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'); } }); } });