我有一个函数将一个函数包装在另一个函数周围,然后将它附加到一个元素。
function addCustomEvent(element, eventName, handler, useCapture) {
var wrappedHandler = function () {
// Do something here.
handler.call();
};
element.addEventListener(eventName, wrappedHandler, useCapture);
}
这很好用,我也想实现这个功能:
removeCustomEvent(element, eventName, handler, useCapture)
所以我想做这样的事情。
var clickHandler= function () { /* ... */ };
addCustomEvent(someElement, "click", clickHandler, false);
removeCustomEvent(someElement, "click", clickHandler, false);
这是一个问题,因为我没有wrappedHandler
中removeCustomEvent
的引用。
我现在能想到的唯一方法是跟踪字典中的handler
及其对应的wrappedHandler
,以便我可以从wrappedHandler
找到handler
在函数内,并将其删除。
但是我不喜欢这种方法,因为浏览器必须有关于哪些处理程序附加的信息,因此创建一个新字典似乎是多余的,浪费内存。
是否有更好,更清洁的方式?
答案 0 :(得分:2)
就个人而言,我只需将addCustomEvent
和removeCustomEvent
包装到单个模块中,并保留一个跟踪绑定处理程序的对象。您认为这“浪费资源”,但实际上,这种方法的影响可以忽略不计。
好处是:您可以轻松扩展模块的开头,处理更复杂的事件处理程序(例如使用touchstart
和touchend
事件模拟移动设备的标签事件)。 / p>
另一种方法是在内部取消绑定事件处理程序,具体取决于事件对象本身
然后,您将不得不重新编写removeCustomEvent
函数来触发特殊事件,以便绑定的处理程序知道您要删除事件侦听器。
//in the wrappedHandler:
var wrappedHandler = function(e)
{
e = e || window.event;
if (e.synthetic === true)
{
e.preventDefault();
e.stopPropagation();
element.removeEventListener(eventName, wrappedHandler, useCapture);//<-- use closure vars
return e;//or return false.
}
//do normal event
handler.apply(this, [e]);//pass event object, and call handler in the same context!
};
var removeCustomEvent = function(event, node, capture)
{
var e, eClass,
doc = node.ownerDocument || (node.nodeType === (document.DOCUMENT_NODE || 9) ? node : document);
if (node.dispatchEvent)
{
if (event === 'click' || event.indexOf('mouse') >= 0)
eClass = 'MouseEvents';
else
eClass = 'HTMLEvents';
e = doc.createEvent(eClass);
e.initEvent(event, !(event === 'change'), true);
//THIS IS THE TRICK:
e.synthetic = true;
node.dispatchEvent(e, true);
return true;
}
if (node.fireEvent)
{
e = doc.createEventObject();
e.synthetic = true;
node.fireEvent('on' + event, e);
return true;
}
event = 'on' + event;
return node[event]();
};
here's a version of this code that is actually documented
我在事件对象上设置了一个synthetic
属性,该属性将传递给事件处理程序。处理程序检查此属性,如果它设置为true
,它将取消绑定侦听器并返回。这不需要你将DOM引用和处理程序保存在一个对象中,但是,我认为你也同意,这也是很多工作。
如果你不介意我这么说,那也感觉非常hacky ......
与:相比:
var binderModule = (function()
{
var module = {},
eventMap = {},
addEvent = function (elem, eventName, handler, capture)
{
var i, wrappedHandler;
if (!eventMap.hasOwnProperty(eventName))
eventMap[eventName] = [];
for (i=0;i<eventMap[eventName].length;++i)
{//look for elem reference
if (eventMap[eventName][i].node === elem)
break;
}
if (i>= eventMap[eventName].length)
{
i = eventMap[eventName].length;//set i to key
eventMap[eventName].push({
node: elem,
handlers: []//keep handlers here, in array for multiple handlers
});
}
wrappedHandler = function(e)
{
//stuff
return handler.apply(this, [e || window.event]);//pass arguments!
};
eventMap[eventNAme][i].handlers.push(wrappedHandler);
return elem.addEventListener(eventName, wrappedHandler, capture);
},
removeEvent(elem, eventName, capture)
{
var i, temp;
if (!eventMap.hasOwnProperty(eventName))
return;//no handlers bound, end here
for (i=0;i<eventMap[eventName].length;++i)
if (eventMap[eventName][i].node === elem)
break;
if (i < eventMap[eventName].length)
{//found element, remove listeners!
//get handlers
temp = eventMap[eventName][i].handlers;
//remove element + handlers from eventMap:
eventMap[evetnName][i] = undefined;
for (i=0;i<temp.length;++i)
elem.removeEventListener(eventName, temp[i], capture);
}
};
module.addCustomEvent = addEvent;
module.removeCustomEvent = removeEvent;
//or, perhaps better:
Object.defineProperty(module, 'addCustomEvent', {value: addEvent});//read-only
Object.defineProperty(module, 'removeCustomEvent', {value: removeEvent});
return module;
}());
请注意,这是跟踪绑定到特定DOM节点的事件处理程序以及如何对其进行管理的基本设置。此代码未完成且未经过测试。它可能包含拼写错误,语法错误和一些一致性问题。但这应该足以让你开始。