EventTarget.addEventListener()

概述

addEventListener() 方法将指定的事件监听器注册到目标对象上,当该对象触发指定的事件时,指定的回调函数就会被执行。 监听事件 可以是一个文档上的元素,  document 本身, window, 或者 XMLHttpRequest.

语法

target.addEventListener(type, listener[, useCapture]);
target.addEventListener(type, listener[, useCapture, wantsUntrusted  ]); // Gecko/Mozilla only
type
表示所监听事件的类型[zh-CN]的一个字符串。
listener
当指定的事件类型发生时被通知到的一个对象。该参数必是实现EventListener接口的一个对象或函数。
useCapture  可选
如果值为true, useCapture 表示用户希望发起捕获。 在发起捕获之后, 只要Dom子树下发生了该事件类型,都会先被派发到该注册监听器,然后再被派发到Dom子树中的注册监听器中。并且向上冒泡的事件不会触发那些发起捕获的事件监听器。进一步的解释可以查看 DOM Level 3 Events 文档。 请注意该参数并不是在所有的浏览器版本中都是可选的。如果没有指定, useCapture 默认为false 。
注意: 如果事件监听器恰好注册到了事件目标上,那么这个事件会处于“目标阶段”,而不是冒泡阶段或者捕获阶段。在目标阶段的事件会触发所有的监听器,而不在乎这个监听器到底在注册时useCapture 参数值是什么。
注意: useCapture 仅仅在现代浏览器比较靠前的几个版本中是可选的。 例如 Firefox 6以前的版本都不是可选的。
wantsUntrusted 
如果该值为true, 则事件能够被不可信的内容所触发。请见 Interaction between privileged and non-privileged pages.

例子

添加一个简单的事件监听器

HTML Content

<table id="outside">
    <tr><td id="t1">one</td></tr>
    <tr><td id="t2">two</td></tr>
</table>
 
 
 
 

JavaScript Content

// 改变t2的函数
function modifyText() {
  var t2 = document.getElementById("t2");
  if (t2.firstChild.nodeValue == "three") {
    t2.firstChild.nodeValue = "two";
  } else {
    t2.firstChild.nodeValue = "three";
  }
}

// 为table添加事件监听器
var el = document.getElementById("outside");
el.addEventListener("click", modifyText, false);
 
 
 
 
 
 
 
 
 
 
 
 
 

在上个例子中,modifyText() 是一个click事件监听器,通过使用addEventListenter注册到table对象上。在表格中任何位置单击都会触动事件并执行modifyText()。

如果你想传参到事件监听函数中,你可以使用匿名函数。

带有匿名函数的事件监听器

HTML Content

<table id="outside">
    <tr><td id="t1">one</td></tr>
    <tr><td id="t2">two</td></tr>
</table>
 
 
 
 

JavaScript Content

// 改变t2值的函数
function modifyText(new_text) {
  var t2 = document.getElementById("t2");
  t2.firstChild.nodeValue = new_text;    
}
 
// 为table对象添加事件监听器
var el = document.getElementById("outside");
el.addEventListener("click", function(){modifyText("four")}, false);
 
 
 
 
 
 
 
 
 

备注

为什么要使用addEventListener?

addEventListener 是W3C DOM中提供的注册事件监听器的方法。它的优点包括:

  • 它允许给一个事件注册多个监听器。在使用DHTML库或者 Mozilla extensions 这样需要保证能够和其他的库或者差距并存的时候非常有用。
  • 它提供了一种更精细的手段控制事件监听器的触发阶段。(即可以选择捕获或者冒泡)。
  • 它对任何DOM元素都是有效的,而不仅仅只对HTML元素有效。

除了这种方法以外,后文会简单阐述一些其他用于注册事件监听器的方法

在时间正在分派时添加监听器

当一个EventListenerEventTarget正在处理事件的时候被注册到EventTarget上,它不会被立即出发,但可能在事件流后面的事件触发阶段被触发,例如可能在捕获阶段添加,然后在冒泡阶段被触发。

多个相同的事件处理器

如果多个相同的 EventListener被注册到同一个EventTarget,而且参数都是相同的,那么重复的实例会被抛弃。所以这么做不会使得 EventListener 被调用两次,也不需要用removeEventListener手动清除多余的EventListener ,因为重复的都被自动抛弃了。

处理过程中 this 的值的问题

通常来说this的值是触发事件的元素的引用,这种特性在为多个相似的元素使用同一个通用事件监听器时非常让人满意。当使用addEventListener() 注册事件的时候,this 会发生变化——应当注意到this的值是由函数调用者传递给函数的。

在前面的例子中,modifyText() 函数中的this 的值是从点击事件中获得的表 “t”。然而与之相对的,在下面的例子中,时间处理器是直接写在HTML源代码中的:

<table id="t" onclick="modifyText();">
. . .

这时modifyText()中的this 的值会变成global (window) 对象的引用。

注意: JavaScript 1.8.5 引入了Function.prototype.bind() 方法,允许制定函数调用时的 this 的值。这使得想要绕开由于调用情况不同,this取值不同的问题变得十分容易 。然而请注意,你应该保留一个listener引用,以便在未来需要的时候能够比较好地移除这listener。

旧版 Internet Explorer 的 attachEvent 方法

对于Internet Explorer来说,在IE 9之前,你必须使用attachEvent 而不是使用标准的方法addEventListener。为了支持IE,前面的例子需要改成这样:

if (el.addEventListener) {
  el.addEventListener('click', modifyText, false); 
} else if (el.attachEvent)  {
  el.attachEvent('onclick', modifyText);
}

使用attachEvent方法有个缺点,是this 的值会变成 window 对象而不是触发事件的元素。

注册事件侦听器的传统方法

addEventListener() 在DOM 2 Events 规范中引入。在这之前,事件监听器应该用以下的方法注册:

// Pass a function reference — do not add '()' after it, which would call the function!
el.onclick = modifyText;

// Using a function expression
element.onclick = function() {
    // ... function logic ...
};

这个方法可以用以替换所以现存click 事件上这个元素已有的事件监听器。这对其他事件是类似的,比如对 blur (onblur)、 keypress (onkeypress)等等。

由于这是DOM 0规范规定了这些方法必须实现,这个方法几乎所有浏览器都支持,而且基本上浏览器之间没有差异。因此通常这个方法被用于动态地注册时间处理器,除非必须使用addEventListener() 才能提供的特殊特性。

内存问题

var i;
var els = document.getElementsByTagName('*');

// Case 1
for(i=0 ; i<els.length ; i++){
  els[i].addEventListener("click", function(e){/*do something*/}, false});
}

// Case 2
function processEvent(e){
  /*do something*/
}

for(i=0 ; i<els.length ; i++){
  els[i].addEventListener("click", processEvent, false});
}

在第一种情况下,每个循环中都会创建一个新的(匿名)函数。在第二种情况下,会使用先前声明的相同的函数作为事件处理器。这样的结果是占用的存储空间更小。而且,在第一种情况中,由于没有保持到匿名函数的引用,它不可能被调用 element.removeEventListener,这是因为我们没有一个可参考的处理器,而在第二种情况,它可以被 myElement.removeEventListener("click", processEvent, false)

浏览器兼容性

特性 Chrome Firefox (Gecko) Internet Explorer Opera Safari (WebKit)
基础支持 1.0 1.0 (1.7 or earlier) 9.0 7 1.0
useCapture 方法是否可行 1.0 6.0 9.0 11.60 (Yes)
特性 Android Firefox Mobile (Gecko) IE Mobile Opera Mobile Safari Mobile
基础支持 1.0 1.0 (1) 9.0 6.0 1.0

Gecko 备注

  • 在Firefox 6之前,如果useCapture 没有显式指定为false,浏览器可能抛出一个异常。在Gecko 9.0 (Firefox 9.0 / Thunderbird 9.0 / SeaMonkey 2.6)之前,如果listener 参数是null,使用addEventListener() 会抛出一个异常,而现在这样做方法会正常返回,但不会有任何效果。

WebKit 备注

  • 尽管WebKit不久前显式地给useCapture 参数添加了[optional] 标记,但是在Safari 5.1和 Chrome 13之前并不支持不填写useCapture参数。

相关链接

规范

DOM Level 2 Events: EventTarget.addEventListener

DOM Level 3 Events: EventTarget.addEventListener

文档标签和贡献者

标签: 
最后编辑者: linmx0130,