我注意到可以直接在对象上分配事件,而无需使用 addEventListener:
document.onload = function(e){
// do stuff..
};
代替:
document.addEventListener('load', function(e){
// do stuff..
});
那么有什么理由我不应该使用第一种方法吗?为什么其他人不使用它?
这似乎也适用于旧 IE(您需要 attachEvent)。
我注意到可以直接在对象上分配事件,而无需使用 addEventListener:
document.onload = function(e){
// do stuff..
};
代替:
document.addEventListener('load', function(e){
// do stuff..
});
那么有什么理由我不应该使用第一种方法吗?为什么其他人不使用它?
这似乎也适用于旧 IE(您需要 attachEvent)。
考虑如果您尝试以下操作会发生什么(我将事件附加到,window
因为这是您应该监听此事件的地方)
window.onload = function (e) {console.log('A');};
window.onload = function (e) {console.log('B');};
对比
window.addEventListener('load', function (e) {console.log('C');}, false);
window.addEventListener('load', function (e) {console.log('D');}, false);
在第一个代码块中,您只会看到"B"
,但从第二个代码块中,您会同时看到"C"
和"D"
。小提琴(请打开控制台查看)。
除了正如公认的答案所显示的那样,直接将处理程序绑定到 DOM 限制了处理程序的数量之外,addEventListener
还有很多东西可以提供:
事件侦听器不需要直接绑定到元素(它不必存在于 DOM 中)。这在使用 ajax 时很有用(将其视为 jQuery 的.on
方法)。
单个侦听器可以处理特定类型的所有事件,因此使用事件侦听器需要更少的资源(这可以加快整体性能)
对于 X 浏览器的兼容性(如 IE8),避免内存泄漏要容易得多:
window.onload = function(e)
{
alert('In IE8, this causes mem-leaks!');
};
var load = function(e)
{//cf @PaulS.'s comment & link on IE8 and symbol bleeding
e = e || window.event;//X-browser stuff
var target = e.target || e.srcElement;//so you can use this callback for all browsers
if (window.removeEventListener)
{//more X-browser stuff
return window.removeEventListener('load',load,false);
}
window.detachEvent('onload',load);//reference callback by variable name
};
if (window.addEventListener)
{
window.addEventListener('load',load,false);
}
else
{//in IE8, addEventListener doesn't exist, but it has a jScript counterpart:
//no mem-leaks in IE AFAIK
window.attachEvent('onload', load);
}
这里有几个你可能会感兴趣的链接(是的,我知道,无耻的自我推销——对不起):
为什么我们需要事件监听器?
IE8 中的内存泄漏和事件委托和关闭
只是为了好玩:我不久前编写的一个脚本,它使用事件委托并适用于 IE、FF、chrome和触摸设备。这比我预期的要棘手一些。
/**
* Copyright 2012, Elias Van Ootegem
* Date: Tue Jul 03 2012 +0100
*/
(function(G,undef)
{
'use strict';
var load,clickHandler,touchHandler,hide,reveal;
hide = function(elem)
{
elem.setAttribute('style','display:none;');
};
reveal = function(show,nextTo)
{
var str = 'display: block; position:relative; left:220px; top: ' + (nextTo.offsetTop - show.parentNode.offsetTop) + 'px;';
show.setAttribute('style',str);
}
load = function()
{
var doc = G.document;
if (G.removeEventListener)
{
G.removeEventListener('load',load,false);
}
else
{
G.detachEvent('onload',load);
}
if (doc.hasOwnProperty('ontouchstart'))
{//We have a touch device
touchHandler = (function(subNavs)
{
var current,divs = (function()
{
var i,r = {};
for (i=0;i<subNavs.length;i++)
{
r[subNavs[i].id] = doc.getElementById(subNavs[i].id + 'd');
hide(r[subNavs[i].id]);
}
return r;
}());
return function(e)
{
e = e || G.event;
if (e.changedTouches.length !== 1)
{//multi-touch
return e;
}
var timer,endListener,coords,target = e.target || e.srcElement;
if (target.tagName.toLowerCase() === 'img' && target.id.match(/^close[0-9]+$/))
{
hide(current);
current = undef;
return e;
}
if (target.tagName.toLowerCase() === 'a')
{
target = target.parentNode;
}
if (target.tagName.toLowerCase() !== 'p' || !target.id || !divs[target.id])
{
if (current === undef)
{
return e;
}
while(target !== doc.body)
{
target = target.parentNode;
if (target === current)
{
return e;
}
}
timer = setTimeout(function()
{
doc.body.removeEventListener('touchend',endListener,false);
clearTimeout(timer);
timer = undef;
},300);
endListener = function(e)
{
doc.body.removeEventListener('touchend',endListener,false);
clearTimeout(timer);
timer = undef;
hide(current);
current = undef;
return e;
};
return doc.body.addEventListener('touchend',endListener,false);
}
coords = {x:e.changedTouches[0].clientX,y:e.changedTouches[0].clientY};
timer = setTimeout(function()
{
doc.body.removeEventListener('touchend',endListener,false);
clearTimeout(timer);
timer = undef;
},300);
endListener = function(e)
{
e = e || G.event;
clearTimeout(timer);
timer = undef;
doc.body.removeEventListener('touchend',endListener,false);
var endCoords,endTarget = e.target || e.srcElement;
if (endTarget !== target)
{
endCoords = {x:e.changedTouches[0].clientX,y:e.changedTouches[0].clientY};
if (Math.abs(coords.x - endCoords.x) < 26 && Math.abs(coords.y - endCoords.y) < 26)
{
endTarget = target;
}
}
if (endTarget !== target)
{
return e;
}
if (current !== undef)
{
hide(current);
current = undef;
}
current = divs[target.id];
reveal(current,target);
};
doc.body.addEventListener('touchend',endListener,false);
};
}(doc.getElementsByClassName('subnavbar')));
return doc.body.addEventListener('touchstart',touchHandler,false);
}
clickHandler = (function(subNavs)
{
var current,divs = (function()
{
var i,r = {};
for (i=0;i<subNavs.length;i++)
{
r[subNavs[i].id] = doc.getElementById(subNavs[i].id + 'd');
hide(r[subNavs[i].id]);
}
return r;
}());
return function(e)
{
e = e || G.event;
var target = e.target || e.srcElement;
if (target.tagName.toLowerCase() === 'img' && target.id.match(/^close[0-9]+$/))
{
hide(current);
current = undef;
return e;
}
if (target.tagName.toLowerCase() === 'a')
{
target = target.parentNode;
}
if (target.tagName.toLowerCase() !== 'p' || !target.className.match(/\bsubnavbar\b/))
{
if (current !== undef)
{
target = (function()
{
while (target !== doc.body)
{
target = target.parentNode;
if (target === current)
{
return current;
}
}
}());
if (target !== current)
{
hide(current);
current = undef;
}
}
return e;
}
if (e.preventDefault)
{
e.preventDefault();
e.stopPropagation();
}
else
{
e.returnValue = false;
e.cancelBubble = true;
}
if (current !== undef)
{
hide(current);
}
current = divs[target.id];
reveal(current,target);
};
}(doc.getElementsByClassName('subnavbar')));
if (doc.body.addEventListener)
{
return doc.body.addEventListener('click',clickHandler,false);
}
return doc.body.attachEvent('onclick',clickHandler);
};
if (G.addEventListener)
{
return G.addEventListener('load',load,false);
}
return G.attachEvent('onload',load);
}(this));