background
There are several minor problems when binding events using addEventListener() or attachEvent() in javascript:
1. The anonymous function added using addEventListener() or attachEvent() cannot be removed.
The code copy is as follows: var oBtn = document.getElementById('btn');
oBtn.addEventListener('click',function(){
alert('button is clicked')
},false)
oBtn.reomveEventListener('click',function(){
alert('button is clicked')
},false)
//The event on oBtn cannot be removed because an anonymous function is passed in
2. In ie6-ie8, the reverse order execution problem of multiple events is bounded using attachEvent().
The code copy is as follows:
var oBtn = document.getElementById('btn');
oBtn.attachEvent('onclick',function(){
alert(1)
})
oBtn.attachEvent('onclick',function(){
alert(2)
})
oBtn.attachEvent('onclick',function(){
alert(3)
})
//Eie9+ Execution order 1, 2, 3
//Execution orders under ie6-ie8 3, 2, 1
Solve the problem
I want to write a cross-browser event binding module so that it can be reused later, and at the same time I want to solve the appeal problem. JQuery uses event queues and data caching mechanisms to solve this problem. I looked at the relevant source code. It was really complicated. I tried some methods myself and barely implemented them. The code is posted in object-oriented, and I don’t want people to see it complicatedly, so I change it into functions to organize it.
The code copy is as follows:
/*Binding event interface
*
*@param {dom-DOM} and {type-string} and {fn-function} Optional parameters {fnName-string}
*@execute Create an event queue and add it to the DOM object properties.
Add event handler (function) to event queue
An identifier can be added to the event handler to delete the specified event handler
*/
function bind(dom,type,fn,fnName){
dom.eventQueue = dom.eventQueue || {};
dom.eventQueue[type] = dom.eventQueue[type] || {};
dom.handler = dom.handler || {};
if (!fnName) {
var index = queueLength(dom,type);
dom.eventQueue[type]['fnQueue'+index] = fn;
}
else {
dom.eventQueue[type][fnName] = fn;
};
if (!dom.handler[type]) bindEvent(dom,type);
};
/*Binding event
*
*@param {dom-DOM} and {type-string}
*@execute Events are bound only once, handler is used to traverse event handlers (functions) in the execution event queue
*@caller bind()
*/
function bindEvent(dom,type){
dom.handler[type] = function(){
for(var guid in dom.eventQueue[type]){
dom.eventQueue[type][guid].call(dom);
}
};
if (window.addEventListener) {
dom.addEventListener(type,dom.handler[type],false);
}
else {
dom.attachEvent('on'+type,dom.handler[type]);
};
};
/*Remove the interface for event
*
*@param {dom-DOM} and {type-string} Optional parameters {fnName-function}
*@execute If there is no identifier, execute unBindEvent()
If there is an identifier, the specified event handler is deleted. If the event queue length is 0, unBindEvent() is executed.
*/
function unBind(dom,type,fnName){
var hasQueue = dom.eventQueue && dom.eventQueue[type];
if (!hasQueue) return;
if (!fnName) {
unBindEvent(dom,type)
}
else {
delete dom.eventQueue[type][fnName];
if (queueLength(dom,type) == 0) unBindEvent(dom,type);
};
};
/*Remove event
*
*@param {dom-DOM} and {type-string}
*@execute Removes the bound event handler and clears the event queue
*@caller unBind()
*/
function unBindEvent(dom,type){
if (window.removeEventListener) {
dom.removeEventListener(type,dom.handler[type])
}
else {
dom.detachEvent(type,dom.handler[type])
}
delete dom.eventQueue[type];
};
/*Judge event queue length
*
*@param {dom-DOM} and {type-string}
*@caller bind() unBind()
*/
function queueLength(dom,type){
var index = 0;
for (var length in dom.eventQueue[type]){
index++;
}
return index;
};
How to use
The code copy is as follows:
var oBtn = document.getElementById('btn');
//Binding event
//Bind three click event functions at the same time for the button
//The execution order under ie6-ie8 remains unchanged
bind(oBtn,'click',function(){
alert(1);
})
bind(oBtn,'click',function(){
alert(2);
},'myFn')
bind(oBtn,'click',function(){
alert(3);
})
//Remove event
//Remove all bound click event functions, support removal of anonymous functions
unBind(oBtn,'click')
//Remove only event functions with identifier myfn
unBind(oBtn,'click','myFn')
Program ideas
The main idea of the program is to add the event queue as an attribute of the dom element object to the dom element without polluting the global environment. This can solve the problem of data storage of multiple event functions of different dom elements binding to different event types.
The code copy is as follows:
// Event queue on dom element
dom{
eventQueue: {
'click' : {
fnQueue1 : function,
myfn : function,
fnQueue3 : function
}
'mouseover' : {
fnQueue1 : function,
fnQueue2 : function
}
}
}
Each time, the event function is first added to the event queue of the corresponding event type, and the event is only bound once. When an event is triggered, the handler event function is executed, and the handler traverses the event function in the execution event queue.
unBind() removes all bound event functions if there is no incoming identifier, supports removing anonymous functions, and removes the specified event functions if there is an identifier.
The program logic is not complicated, and there may be bugs and performance problems. If you are interested, you can guide and communicate.