冒泡和捕获
字数统计:1.4k字目录
事件流
描述的是从页面中接收事件的顺序。
事件冒泡和事件捕获分别由微软和网景公司提出,这两个概念都是为了解决页面中事件流(事件发生顺序)的问题。1
2
3<div id="outer">
<p id="inner">Click me!</p>
</div>
上面的代码当中一个div元素当中有一个p子元素,如果两个元素都有一个click的处理函数,那么我们怎么才能知道哪一个函数会首先被触发呢?
事件冒泡
冒泡型事件:事件按照从最特定的事件目标到最不特定的事件目标(document对象)的顺序触发。`
事件冒泡可以形象地比喻为把一颗石头投入水中,泡泡会一直从水底冒出水面。也就是说,事件会从最内层的元素开始发生,一直向上传播,直到document对象。
因此上面的例子在事件冒泡的概念下发生click事件的顺序应该是: p -> div -> body -> html -> document
事件捕获
捕获型事件(event capturing):事件从最不精确的对象(document 对象)开始触发,然后到最精确(也可以在窗口级别捕获事件,不过必须由开发人员特别指定)
上面的例子在事件捕获的概念下发生click事件的顺序应该是: document -> html -> body -> div -> p
IE只支持事件冒泡,Chrome,Mozilla, Opera 7 和 Konqueror两种都支持,旧版本的Opera’s 和 iCab两种都不支持 。
捕获和冒泡过程图

1 |
|
并且分别在obj1,obj2上绑定了一个点击事件,由于addEventListener的第三个参数为false,所以页面是在冒泡阶段处理绑定事件。此时整个页面可以有三种行为出现:
- 点击文字welcome时,弹出hello。
此时就只触发了绑定在obj1上的点击事件。具体冒泡实现过程如下:welcome 属于文本节点,点击后,开始从文本节点查找,当前文本节点没有绑定点击事件,继续向上找,找到父级(id为obj1的div),有绑定的点击事件,执行,再向上找,body,没有绑定点击事件,再到html,document,都没再有绑定的点击事件,好,整个冒泡过程结束。 - 点击文字hello时,先弹出world,再弹出hello
- 点击world时,弹出hello。
addEventListener的第三个参数
lement.addEventListener(event, function, useCapture)
第一个参数是需要绑定的事件,第二个参数是触发事件后要执行的函数。而第三个参数默认值是false,表示在事件冒泡的阶段调用事件处理函数,如果参数为true,则表示在事件捕获阶段调用处理函数。
我们想要在点击每个h5标签时,弹出对应的innerHTML 。常规做法是遍历每个h5,然后在每个h5上绑定一个点击事件,这种做法在h5较少的时候可以使用,但如果有一万个h5,那就会导致性能降低。这时就需要事件代理出场了。
事件代理
使用事件代理的好处不仅在于将多个事件处理函数减为一个,而且对于不同的元素可以有不同的处理方法
1 | obj1.addEventListener('click',function(e){ |
由于事件冒泡机制,点击了h5后会冒泡到div,此时就会触发绑定在div上的点击事件,再利用target找到事件实际发生的元素,就可以达到预期的效果。
阻止冒泡的方法,阻止默认事件的方法(兼容IE)
w3c的方法是e.stopPropagation(),IE则是使用e.cancelBubble = true
阻止事件的传播兼容
1 | function(e){ |
阻止冒泡事件的兼容性处理1
2
3
4
5
6
7function stopBubble(e) {
if(e && e.stopPropagation) { //非IE
e.stopPropagation();
} else { //IE
window.event.cancelBubble = true;
}
}
阻止默认事件
w3c的方法是e.preventDefault(),IE则是使用e.returnValue = false;
我们给一个dom同时绑定两个点击事件,一个用捕获,一个用冒泡,会执行几次事件,会先执行冒泡还是捕获?首是进入捕获阶段,直到达到目标元素,再进入冒泡阶段
DOM事件流
“DOM2级事件”规定的事件流包括三个阶段:事件捕获、处于目标阶段和事件冒泡阶段。发生的顺序是事件捕获阶段==>目标阶段==>事件冒泡阶段。 DOM2级事件规定 :捕获阶段不会涉及目标事件。