一、事件流javascript
事件冒泡html
IE的事件流叫作事件冒泡(event bubbling),即事件开始时由最具体的元素(文档中嵌套层次最深的那个节点)接收,而后逐级向上传播到较为不具体的节点(文档)。java
事件捕获浏览器
事件捕获的思想是不太具体的节点应该更早的接收到事件,而最具体的节点应该在最后接收到节点。事件捕获的用意在于事件到达预约目标以前捕获它。函数
DOM事件流this
“DOM2级事件流”规定的事件流包括三个阶段:事件捕获阶段、处于目标阶段和冒泡阶段。首先发生的是事件捕获,为截获事件提供了机会。而后是实际的目标接收到事件。最后一个阶段是冒泡阶段,能够在这个阶段对事件做出响应。以简单的HTML页面为例,单击<div>元素会按照下图顺序触发事件spa
在DOM事件流中,实际的目标(<div>元素)在捕获阶段不会接收到事件。这意味着在捕获阶段,事件从document到<html>再到<body>后就中止了。下一个阶段是“处于目标”阶段,因而事件在<div>上发生,并在事件处理中被当作冒泡阶段的一部分。而后冒泡阶段发生,事件又传播回文档。code
多数支持DOM事件流的浏览器都实现了一种特定行为;即便“DOM2级事件”规范明确要求捕获阶段不会涉及事件的目标,但Safari、Chrome、Firefox和Opera9.5及更高版本都会在捕获阶段触发事件对象上的事件。结果,就是有两个机会在目标对象上面操做事件。htm
Opera、Firefox、Chrome和Safari都支持DOM事件流;IE不支持DOM事件流。对象
二、事件处理程序(或事件侦听器)
事件是用户或浏览器自身执行的某种动做。诸如click、load和mouseover,都是事件的名字。 而响应某个事件的函数就叫作事件处理程序(或事件侦听器)。事件处理程序的名字以“on”开头,所以click事件的事件处理程序就是onclick等。为事件指定处理程序的方式有好几种。
HTML事件处理程序
某个元素支持的每种事件,均可以使用一个与相应事件处理程序同名的HTML特性指定。如:
<input type="button" value="Click me" onclick="alert('Clicked')"/>
<script type="text/javascript"> function showMessage(){ alert("Hello World!"); } </script> <input type="button" value="Click me" onclick="showMessage()"/>
在HTML中指定事件有两个缺点。首先,存在一个时差问题。由于用户可能在HTML元素一出如今页面上就触发相应的事件,但当时事件处理程序有可能尚不具有执行条件。例如前面的例子,假设showMessage函数在按钮下方页面最底部定义的,若是用户在页面解析showMessage函数以前就单击了按钮,就会引起报错。第二个肯定是HTML与JavaScript代码紧密耦合。若是要更换事件处理程序,就要改动两个地方。
DOM0级事件处理程序
经过JavaScript指定事件处理程序的传统方式,就是讲一个函数赋值给一个事件处理程序属性。要使用JavaScript指定事件处理程序,首先必须取得一个要操做的对象的引用。
每一个元素(包括window和document)都有本身的事件处理程序属性,这些属性一般小写,例如onclick。将这种属性的值设置成一个函数,就能够指定事件处理程序。
使用DOM0级方法指定的事件处理程序被认为是元素的方法,所以是在元素的做用域中运行,换句话说,程序中的this引用当前元素。
var btn = document.getElementById("myBtn"); btn.onclick = function(){ alert(this.id); //"myBtn" };
能够在事件处理程序中经过this访问元素的任何属性和方法,以这种方式添加的事件处理程序会在事件流中的冒泡阶段被处理。
能够删除经过DOM0级方法指定的事件处理程序,只要将事件处理程序属性的值设为null便可。
btn.onclick = null; //删除事件处理程序
DOM2级事件处理程序
“DOM2级事件”定义了两个方法,用于处理指定和删除事件处理程序的操做:addEventListener()和removeEventListener()。全部DOM节点中都包含这两个方法,而且它们都接受三个参数:要处理的事件名、做为事件处理程序的函数和一个布尔值。最后这个布尔值若是是true,表示在捕获阶段调用事件处理程序;若是是false,表示在冒泡阶段调用事件处理程序。
与DOM0级方法同样,DOM2级方法天际的事件处理程序也是在其依附的元素的做用域中进行。使用DOM2级方法添加事件处理程序的主要好处是能够添加多个事件处理程序。来看下面的例子:
btn.addEventListener("click",function(){ alert(this.id); },false); btn.addEventListener("click",function(){ alert("Hello World!"); },false);
这里为按钮多添加了两个事件处理程序。这两个事件处理程序会按照添加它们的顺序触发,所以首先会显示元素ID,其次会显示“Hello World!”消息。
经过addEventListener()添加的事件处理程序只能使用removeEventListener来移除;移除时传入的参数与添加处理程序时使用的参数相同。这也意味着经过addEventListener()添加的匿名函数将没法移除,以下:
var btn = document.getElementById("myBtn"); btn.addEventListener("click",function(){ alert(this.id); },false); btn.removeEventListener("click",function(){ //没有用! alert(this.id); },false);
var btn = document.getElementById("myBtn"); var handler = function(){ alert(this.id); }; btn.addEventListener("click",handler,false); btn.removeEventListener("click",handler,false); //有效!
大多数状况下,都是将事件处理程序添加到事件流的冒泡阶段,这样能够最大限度的兼容各类浏览器。最好只在须要事件到达目标以前截获它的时候将事件处理程序添加到捕获阶段。若是不是特别须要,咱们不建议在事件捕获阶段注册事件处理程序。
Firefox、Safari、Chrome和Opera支持DOM2级事件处理程序
IE事件处理程序
IE实现了与DOM相似的两个方法:attachEvent()和detachEvent()。这两个方法接受相同的两个参数:事件处理程序名称与事件处理程序函数。因为IE只支持事件冒泡,因此经过attachEvent()添加的事件处理程序都会被添加到冒泡阶段。
var btn = document.getElementById("myBtn"); btn.attachEvent("onclick",function(){ alert("Clicked"); });
注意:第一个参数为“onclick”,而非DOM的addEventListener()方法中的"click"。
在IE中使用attachEvent()与使用DOM0级方法的主要区别在于事件处理程序的做用域。DOM0级事件处理程序会在其所属元素的做用域内运行;在使用attachEvent()方法的状况下,事件处理程序会在全局做用域中运行,所以this等于window。在编写跨浏览器的代码时,牢记这一点区别很是重要。
attachEvent()也能够为一个元素添加多个事件处理程序,来看下面的例子:
var btn = document.getElementById("myBtn"); btn.attachEvent("onclick",function(){ alert("Clicked"); }); btn.attachEvent("onclick",function(){ alert("Hello World!"); });
与DOM方法不一样的是,这些事件处理程序不是以添加它们的顺序执行,而是以相反的顺序被触发。单击这个例子中的按钮,首先看到的是“Hello World!”,而后才是“Clicked”。
使用attachEvent()添加的事件能够经过detachEvent()来移除,条件是必须提供相同的参数。与DOM方法同样,添加的匿名函数将不能被移除。
var btn = document.getElementById("myBtn"); var handler = function(){ alert("Clicked"); }; btn.attachEvent("onclick",handler); btn.detachEvent("onclick",handler);