昨天遇到一段js代码里面的addEventListener方法竟然有三个参数,去谷歌搜了一下,觉得这个概念很有意思,值得总结一下写成博客。
useCapture
addEventListener()中的第三个参数是Boolean类型的值,代表第二个参数handler是否在第一个参数Event的capture阶段使用。
事件(Event)在事件目标(EventTarget)中的顺序
当DOM元素之间有包含关系时,发生在其上的事件有两种顺序:
- Capturing
- Bubbling
Capturing就是从上往下:
| |
---------------| |-----------------
| element1 | | |
| -----------| |----------- |
| |element2 \ / | |
| ------------------------- |
| Event CAPTURING |
-----------------------------------
这种情况下,事件发生后,注册在element1上的handler会先触发,注册在element2上的handler会后触发。
Bubbling就是从下往上:
/ \
---------------| |-----------------
| element1 | | |
| -----------| |----------- |
| |element2 | | | |
| ------------------------- |
| Event BUBBLING |
-----------------------------------
这种情况下,事件发生后,注册在element2上的handler会先触发,注册在element1上的handler会后触发。
W3C标准中的事件顺序
| | / \
-----------------| |--| |-----------------
| element1 | | | | |
| -------------| |--| |----------- |
| |element2 \ / | | | |
| -------------------------------- |
| W3C event model |
------------------------------------------
在w3c模型中,事件会先从上往下,到事件目标元素后,再从下往上,一直到最外面的元素。
代码实例
<div id="parent">parent div
<div id="child">child div</div>
</div>
const parent = document.querySelector('#parent');
const child = document.querySelector('#child');
function first() {
alert('first');
}
function second() {
alert('second');
}
parent.addEventListener('click', second, false);
child.addEventListener('click', first);
点击child元素,会先弹出first,然后弹出second。我们来分析一下为什么会这样:
click事件在child元素发生后,第一步是capturing阶段,先从上往下寻找child元素的锚定元素(Ancestor Element)中是否有可以触发的handler,如果useCapture参数是true的话就会在此阶段触发,结果发现没有可以触发的handler。
click事件到达child元素后触发first方法,然后开始bubbling阶段,到达parent元素时发现有用于此阶段的handler,触发second方法。
如果我们把代码改一下,变成:
parent.addEventListener('click', second, true);
child.addEventListener('click', first);
点击child元素,会先弹出second,然后弹出first。分析过程和前面很类似:
click事件在child元素发生后,第一步是capturing阶段,先从上往下寻找child元素的锚定元素(Ancestor Element)中是否有可以触发的handler,发现可以触发second。
click事件到达child元素后触发first方法,然后开始bubbling阶段,到达parent元素时发现有用于此阶段的handler,没有发现可以触发的handler。