关于attachEvent和addEventListener事件监听

时间:2021-09-29 04:37:11

一般在用JS给元素增加事件的时候,使用的方法为:

<span style="font-size:18px;">obj.onclick=method</span>

这种方法简单高效,但存在一个问题,如果对同一个元素同时添加同一个事件的时候,会造成前面的添加效果失败,只运行最后一个,例如:

<span style="white-space:pre"></span>oBtn = document.getElementById('btn1');
<span style="white-space:pre"></span>oBtn.onclick = function() {
alert('aaa');
};
oBtn.onclick = function() {
alert('bbb');
};
oBtn.onclick = function() { //只会执行ccc,前两个相同元素的相同事件被覆盖了
alert('ccc');
};


这时候,我们就需要用到事件监听函数了。W3C标准的方法为element.addEventListener(element,type,fn,useCapture),

该方法定义的事件依照定义的顺序执行下去,参数分别为:

1.element:需要添加的事件元素

2.type:事件名称,例如点击事件click,鼠标移入事件mouseover--->注意,这里的事件前面不需要'on'

3.fn:事件监听函数,即监听到type事件之后需要执行的函数。

4.useCapture:boolean值,只接收true或false,通常建议为false。

例如:

oBtn.addEventListener('click', a, false); //使用事件监听可以让相同元素的相同事件顺序执行,第一个执行
oBtn.addEventListener('click', b, false); //第二个执行
oBtn.addEventListener('click', c, false); //第三个执行
执行顺序为a->b->c

兼容性:在FF/Chrome/Opera/IE>8(不包含8)时候能正常运行。

如果需要兼容IE8及以下,则需要另一个方法element.attechEvent(type,function);该方法的参数为:

1.element需要添加的事件元素

2.type:事件方法,这个type和上面的区别是,需要加"on",例如点击事件,type='onclick'。

3.function:处理函数。

例如:

oBtn.attachEvent('onclick', a);//第三个执行
oBtn.attachEvent('onclick', b);//第二个执行
oBtn.attachEvent('onclick', c);//第一个执行

对于兼容性,需要注意点:

1.该方法只在IE下使用。且只在IE11以下使用,在IE11检测无效

2.在IE8及以下时,运行顺序为倒序,即最后一个定义的第一个执行,c->b->a。

3.在IE8以上时候,是先定义先执行,a->b->c。建议在IE8以上浏览器中使用addEventListener()方法

----------------------------------------------------------------

给出一些前人们写好的兼容通用方法:

function addEvent(elm, evType, fn, useCapture) {
if (elm.addEventListener) {
elm.addEventListener(evType, fn, useCapture);//DOM2.0
return true;
}
else if (elm.attachEvent) {
var r = elm.attachEvent(‘on‘ + evType, fn);//IE5+
return r;
}
else {
elm['on' + evType] = fn;//DOM 0
}
}

下面是 Dean Edwards的版本:

function addEvent(element, type, handler) {
//为每一个事件处理函数分派一个唯一的ID
if (!handler.$$guid) handler.$$guid = addEvent.guid++;
//为元素的事件类型创建一个哈希表
if (!element.events) element.events = {};
//为每一个"元素/事件"对创建一个事件处理程序的哈希表
var handlers = element.events[type];
if (!handlers) {
handlers = element.events[type] = {};
//存储存在的事件处理函数(如果有)
if (element["on" + type]) {
handlers[0] = element["on" + type];
}
}
//将事件处理函数存入哈希表
handlers[handler.$$guid] = handler;
//指派一个全局的事件处理函数来做所有的工作
element["on" + type] = handleEvent;
};
//用来创建唯一的ID的计数器
addEvent.guid = 1;
function removeEvent(element, type, handler) {
//从哈希表中删除事件处理函数
if (element.events && element.events[type]) {
delete element.events[type][handler.$$guid];
}
};
function handleEvent(event) {
var returnValue = true;
//抓获事件对象(IE使用全局事件对象)
event = event || fixEvent(window.event);
//取得事件处理函数的哈希表的引用
var handlers = this.events[event.type];
//执行每一个处理函数
for (var i in handlers) {
this.$$handleEvent = handlers[i];
if (this.$$handleEvent(event) === false) {
returnValue = false;
}
}
return returnValue;
};
//为IE的事件对象添加一些“缺失的”函数
function fixEvent(event) {
//添加标准的W3C方法
event.preventDefault = fixEvent.preventDefault;
event.stopPropagation = fixEvent.stopPropagation;
return event;
};
fixEvent.preventDefault = function() {
this.returnValue = false;
};
fixEvent.stopPropagation = function() {
this.cancelBubble = true;
};

功能非常强悍,解决IE的this指向问题,event总是作为第一个参数传入,跨浏览器就更不在话下。

HTML5工作组的版本:

var addEvent=(function(){
if(document.addEventListener){
return function(el,type,fn){
if(el.length){
for(var i=0;i<el.length;i++){
addEvent(el[i],type,fn);
}
}else{
el.addEventListener(type,fn,false);
}
};
}else{
return function(el,type,fn){
if(el.length){
for(var i=0;i<el.length;i++){
addEvent(el[i],type,fn);
}
}else{
el.attachEvent(‘on‘+type,function(){
return fn.call(el,window.event);
});
}
};
}
})();