冒泡和捕获
在 Chrome 89.0.4363.0 以及之后版本中,目标元素(at_target)的触发事件顺序不再按照注册顺序触发!而是按照先捕获再冒泡的形式依次执行!
addEventListener 的第三个参数默认是 false,在冒泡阶段(bubble)触发
阻止冒泡,e.stopPropagation
e.preventDefault() 可以阻止浏览器默认行为.比如,让a标签取消默认的跳转功能.
为了避免因为版本的不同而造成业务上的问题,我们只需要将所有目标元素代码的顺序都按照先书写捕获事件代码,再书写冒泡事件代码,就可以兼容本次的更新。
# 如何识别事件是在捕获,目标对象,还有冒泡阶段进行的?
eventPhase 可以来识别
eventPhase等于0,这个时间,没有事件正在被处理
eventPhase等于1,捕获阶段
eventPhase等于2,事件处理程序处于目标对象上
eventPhase等于3,冒泡阶段调用的事件处理程序
注意:处于目标阶段时,捕获和冒泡都是 2
# 事件注册
一般使用 addEventListener 来注册事件,它接受三个参数:
- 字符串:处理的事件名称,如点击事件 click;
- 回调函数:事件处理程序,即要绑定的函数体;
- 指定是在事件冒泡还是事件捕获阶段处理参数,可以是布尔值,也可以是对象
- true 则作为捕获事件处理;
- false 则作为冒泡事件处理(默认)。
第三个参数是对象时,可以使用以下几个属性:
capture
:布尔值,和第三个参数作为布尔值时作用一样:false 为冒泡,true 为捕获once
:布尔值,值为 true 表示该回调只会调用一次,调用后会移除监听passive
:布尔值,表示永远不会调用 preventDefault
一般来说,我们可以通过使用 stopPropagation 来阻止事件的进一步传播,即阻止事件冒泡。
// stopPropagation() 可以阻止捕获和冒泡
e.stopPropagation();
// stopImmediatePropagation() 也可以阻止捕获和冒泡,但主要作用是阻止监听同一事件的其他事件监听器被调用
e.stopImmediatePropagation();
1
2
3
4
2
3
4
- event.target 指向触发事件流程的元素,且不会改变。
- this 指向的是当前所执行事件的注册元素,也就是 e.currentTarget。
- 捕获止于 event.target,冒泡始于 event.target。
- 主流浏览器都默认在冒泡阶段进行事件注册,所以,只有阻止冒泡的方法而没有阻止捕获的方法。
# 事件触发三阶段
事件捕获阶段
:window 往事件触发处传播,遇到注册的捕获事件会触发处于目标阶段
:传播到事件触发处时触发注册的事件事件冒泡阶段
:从事件触发处往 window 传播,遇到注册的冒泡事件会触发
假设在 DOM 结构里面有 text 的这样一个标签,给这个标签绑定了一个点击事件,那么在点击这个标签的时候是怎么执行事件的呢?
- 首先是事件捕获阶段,会通过 window、document、body、div、text 这样的顺序一直往下捕获事件。
- 然后是处于目标阶段,到 text 标签处触发绑定的点击事件。
- 最后是事件冒泡阶段,事件是在冒泡阶段做出响应的。冒泡阶段通过 text 、div、body、document、window 这样的顺序往上冒泡,假如在 div 或者 body 上面也绑定了对应的 onclick 事件,那么会按顺序触发响应。
不同浏览器中事件的触发顺序不同,有些浏览器是按照代码注册的顺序,有些是先捕获再冒泡,为了不出 bug
,建议在书写代码的时候按照先捕获再冒泡的事件顺序来书写。
# 事件代理
如果一个节点中的子节点是动态生成的,那么子节点需要注册事件的话可以注册在父节点上。
<ul id="proxy">
<li>主页</li>
<li>文章</li>
<li>公告</li>
<li>简介</li>
</ul>
let proxy = document.querySelector('#proxy')
proxy.addEventListener('click', (event) => {
let target = event.target; // 当前点击的元素
if (target.nodeName.toLowerCase() == 'li') {
console.log('click:' + target.innerHTML);
}
})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
2
3
4
5
6
7
8
9
10
11
12
13
14
这种方式相较于直接给目标注册事件来说,有以下优点:
- 可以减少内存占用,减少事件注册
- 不需要给子节点注销事件
最近更新时间: 2021/08/25 17:25:09
- 01
- 2023/07/03 00:00:00
- 02
- 2023/04/22 00:00:00
- 03
- 2023/02/16 00:00:00
v1.4.14