事件捕获和事件冒泡
“DOM2级事件”规定的事件流包括三个阶段:事件捕获、处于目标阶段和事件冒泡。首先发生的是事件捕获,从外部节点到内部节点依次遍历,为截获事件提供了机会。然后是实际的目标接收到事件。最后一个阶段是冒泡阶段,从目标元素逐层冒泡到外部元素<body>,可以在这个阶段对事件做出响应。IE9、 Opera、 Firefox、 Chrome 和 Safari 都支持 DOM 事件流; IE8 及更早版本不支持 DOM 事件流。
Event Handler 的常见用法
事件处理程序名称是事件名称前加on,如onclick、onload. 为事件指定事件处理程序的方法包括:
1)HTML事件处理程序:
通过HTML元素的特性指定:
<input type="button" value="Click Me" onclick="alert('Clicked')" />
最大缺点:HTML和JavaScript紧密耦合,不建议采用。
2)DOM0级事件处理程序:
通过 JavaScript 指定事件处理程序的传统方式,就是将一个函数赋值给一个事件处理程序属性。首先必须取得一个要操作的对象的引用。每个元素(包括 window 和 document)都有自己的事件处理程序属性,这些属性通常全部小写,例如 onclick。将这种属性的值设置为一个函数,就可以指定事件处理程序。
var btn = document.getElementById("myBtn");
//为属性赋值匿名函数
btn.onclick = function(){
alert("Clicked");
};
事件作用域:使用 DOM0 级方法指定的事件处理程序被认为是元素的方法。因此,这时候的事件处理程序是在元素的作用域中运行;换句话说,程序中的 this 引用当前元素。
移除方式:删除通过 DOM0 级方法指定的事件处理程序,只要像下面这样将事件处理程序属性的值设置为 null 即可:
btn.onclick = null; //删除事件处理程序
还记得怎么删除对象实例属性吗?使用delete算符,删除后实例属性就没了,但是原型属性还在。
缺点:同一个事件添加两个事件处理程序会导致后一个覆盖前一个。原因在于一个事件处理程序就是一个属性,为一个属性赋两个值,后一个会覆盖前一个。
3)DOM2 级事件处理程序
“ DOM2 级事件” 定义了两个方法,用于处理绑定和删除事件处理程序的操作:
addEventListener()和 removeEventListener()。
所有 DOM 节点中都包含这两个方法,并且它们都接受 3 个参数:要处理的事件名(不带on)、作为事件处理程序的函数和一个布尔值。最后这个布尔值参数如果是 true,表示在捕获阶段调用事件处理程序;如果是 false,表示在冒泡阶段调用事件处理程序。
/*为一个按钮添加了 onclick 事件处理程序,而且该事件会在冒泡阶段被触发*/
var btn = document.getElementById("myBtn");
btn.addEventListener("click", function(){
alert(this.id);
}, false);
事件作用域:与 DOM0 级方法一样,这里添加的事件处理程序也是在其依附的元素的作用域中运行。使用 DOM2 级方法添加事件处理程序的主要好处是可以添加多个事件处理程序,多事件处理程序会按照添加它们的顺序触发。IE9、 Firefox、 Safari、 Chrome 和 Opera 支持 DOM2 级事件处理程序,对IE8及以下版本有专用事件处理程序。
移除方式:通过 addEventListener()添加的事件处理程序只能使用 removeEventListener()来移除;移除时传入的参数与添加处理程序时使用的参数相同。这也意味着通过 addEventListener()添加的匿名函数将无法通过removeEventListener()移除,这是因为匿名函数每次出现都是一次调用,命名函数每次出现是一次引用。因此建议使用命名函数作为eventhandler的函数参数。
大多数情况下,都是将事件处理程序添加到事件流的冒泡阶段(最后一个参数是false),这样可以最大限度地兼容各种浏览器,jQuery和React使用冒泡机制,解决了兼容性问题。
4)IE事件处理程序(非标准方法)
IE 实现了与 DOM 中类似的两个方法: attachEvent()和 detachEvent()。这两个方法接受相同的两个参数:事件处理程序名称与事件处理程序函数。由于 IE8 及更早版本只支持事件冒泡,所以通过attachEvent()添加的事件处理程序都会被添加到冒泡阶段(DOM2标准建议采用冒泡阶段,但是也可以采用捕获阶段)。
var btn = document.getElementById("myBtn"); //取得DOM元素
btn.attachEvent("onclick", function(){ //注意使用了带on的事件名和匿名函数
alert("Clicked");
});
注意:(a) attachEvent()的第一个参数是"onclick",而非 DOM 的 addEventListener()方法中的"click"。(b) 在使用 attachEvent()方法的情况下,事件处理程序会在全局作用域中运行,因此 this 等于 window。在使用 DOM0 和DOM2标准方法的情况下,事件处理程序会在其所属元素的作用域内运行。(c)默认添加在在冒泡阶段。(d)可以添加多个事件处理程序,多个事件处理程序的执行顺序和DOM2 相反,也就是和添加顺序相反。
var btn = document.getElementById("myBtn");
btn.attachEvent("onclick", function(){
alert(this === window); //true
});
移除:使用 attachEvent()添加的事件可以通过 detachEvent()来移除,条件是必须提供相同的参数。与 DOM 方法一样,这也意味着添加的匿名函数将不能被移除。不过,只要能够将对相同命名函数的引用传给 detachEvent(),就可以移除相应的事件处理程序。
5) 跨浏览器的事件处理程序
可以通过能够隔离浏览器差异的JavaScript库或者创建兼容各大浏览器差异的事件处理方法,库使用可以参照jQuery,这里不介绍。兼容各大浏览器差异的事件处理方法包括addHandler()和removeHandler(),都属于EvenUtil对象,接收相同的参数:要操作的元素、事件名称、事件处理程序函数。
这两个方法首先都会检测传入的元素中是否存在 DOM2 级方法。如果存在 DOM2 级方法,则使用该方法:传入事件类型、事件处理程序函数和第三个参数 false(表示冒泡阶段)。如果存在的是 IE 的方法,则采取第二种方案。注意,为了在 IE8 及更早版本中运行,此时的事件类型必须加上"on"前缀。最后一种可能就是使用 DOM0 级方法(在现代浏览器中,应该不会执行这里的代码)。此时,我们使用的是方括号语法来将属性名指定为事件处理程序(add),或者将属性设置为 null(remove)。
使用方法如下:
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。