先看下面的示例代码:
<html xmlns="http://www.w3.org/1999/xhtml"> <head> <title>JavaScript 中的事件冒泡与事件捕获</title> </head> <body> <div id="Red" style="200px;height:200px;background-color:red;padding:20px;"> <div id="Bule" style="160px;height:160px;background-color:blue;padding:20px;"> <div id="Yellow" style="120px;height:120px;margin:auto;background-color:yellow;padding:20px;"> <div id="Green" style="80px;height:80px;margin:auto;background-color:green;padding:20px;"></div> </div> </div> </div> </body> </html>
效果如下图所示:
考虑这种情况,我们用鼠标点击最中间的 绿色,触发了绿块DIV的点击事件,那是不是也触发了它的父级 黄色块的点击事件,以及祖先级别的 蓝色以及红色块的点击事件?
早期的浏览器开发商网景以及微软一致的认为该点击事件确实触发了父级和祖先级别的点击事件!!!
一、事件流
事件流描述的是从页面中接收事件的顺序,虽然IE以及Netscape都承认事件流的存在,但是却提出了差不错完全相反的事件流概念。IE的事件流是 事件冒泡流,而Netscape的事件流是 事件捕获流。
二、事件冒泡流
事件冒泡流的意思就是事件会从最开始触发的那个元素开始,一级级的向上传播并触发祖先级别对应的事件,直至Document 对象为止。
因此如果我们点击图中的绿色块 click 事件发生的顺序应该是 Green -> Yellow -> Blue -> Red -> body -> html -> document。
三、事件捕获流
事件捕获流与事件冒泡流相反,事件会从最外层开始触发,直至最具体的元素为止。
因此如果我们点击图中的绿色块 click 事件发生的顺序应该是 document -> html -> body -> Red -> Blue -> Yellow -> Green。
四、事件流的实现
W3C的 “DOM2级事件” 中规定的事件流同时支持了事件捕获阶段和事件冒泡阶段。我们可以使用 “DOM2级事件” 提供的两个方法 addEventListener()和 removeEventListener() 来为一个特定的元素绑定或者删除一个事件处理函数:
element.addEventListener(event, function, useCapture)
element.removeEventListener(event, function, useCapture)
event : 要处理的事件名
function:事件处理程序的函数
useCapture:布尔值 指定使用哪种事件流。false 采用事件冒泡流,true 采用事件捕获流。
请看以下 JavaScript 代码:
<script type ="text/javascript"> var div = document.getElementsByTagName("div"); for (var i = 0; i < div.length; i++) { div[i].addEventListener("click", showColor, false); // false 代表冒泡事件流, true 代表捕获事件流 } function showColor() { alert("触发的DIV的颜色是: " + this.id); } </script>
点击最里面的绿色块
当 addEventListener(event, function, useCapture) 的 useCapture 参数为 false 时,依次弹出 Green Yellow Blue Red。
当 addEventListener(event, function, useCapture) 的 useCapture 参数为 true时,依次弹出 Red Blue Yellow Green。
题外记:
今天试了另外一段 JS 代码:
<script type ="text/javascript"> var div = document.getElementsByTagName("div"); for (var i = 0; i < div.length; i++) { var useCapture = true; if (i%2==0) useCapture = false; div[i].addEventListener("click", showColor, useCapture); // false 代表冒泡事件流, true 代表捕获事件流 } function showColor() { alert("触发的DIV的颜色是: " + this.id); } </script>
注意我加粗加红的那段代码,分别给几个div设置了不同的 useCapture.
再次点击绿色块Green时,依次弹出的是 Blue Green Yellow Red.
是因为我们给 Blue块和Green块设置的 useCapture 的值为true 即 事件捕获. Yellow块和Red块依然是 false 即 冒泡事件.
当我们点击绿色块Green时,会先找其祖先级别元素中采用 事件捕获 的元素,一直捕获到当前的元素,然后接着冒泡,但会跳过 事件捕获 的元素,一直到document.
总结起来就一句话: 任何发生在 W3C “DOM2级事件” 中的事件,首是进入捕获阶段,直到达到目标元素,再进入冒泡阶段。