关于事件流机制的理解以及对e.target 和 e.currentTarget问题处理
一 DOM事件流
DOM(文档对象模型)结构是一个树型结构,当一个HTML元素产生一个事件时,该事件会在元素节点与根结点之间的路径传播,路径所经过的结点都会收到该事件,这个传播过程可称为DOM事件流。
上面这句话来自百度百科:DOM事件流,该如何理解这句话呢,如图所示,
当有事件触发时,从DOM的根节点开始,向内传递,这一过程可以理解成①②③④的捕获阶段;如果图中的d节点被触发,事件整个传递到达目标阶段,该阶段结束后,事件会向上传递,这一过程按照水底的气泡一样向上漂,称之为的⑤⑥⑦⑧ 冒泡阶段
结合图和上面的描述可以总结为
在DOM兼容浏览器中,事件流分为3个阶段:
- 捕获阶段:事件从Document节点自上而下向目标节点传播的阶段;
- 目标阶段:真正的目标节点正在处理事件的阶段;
- 冒泡阶段:事件从目标节点自下而上向Document节点传播的阶段
二 捕获事件流
捕获事件流可以在支持W3C 标准的浏览器中使用addEventListener处理,在菜鸟教程:addEventListener 中在线体验.
该函数有三个参数:
- 事件名
- 触发执行函数
- 冒泡阶段还是捕获阶段执行,默认是在冒泡阶段执行
为了理解这个问题,我在网上看到一道十分有意思的题 事件流经典问题:e.target 和 e.currentTarget 有什么区别? ,一起来看下,加深理解.
<div id="a">
<div id="b">
<div id="c">
<div id="d">点击这里</div>
</div>
</div>
</div>
const a = document.getElementById('a')
const b = document.getElementById('b')
const c = document.getElementById('c')
const d = document.getElementById('d')
a.addEventListener('click', (e) => {
const {
target,
currentTarget
} = e
console.log(`target是${target.id}`)
console.log(`currentTarget是${currentTarget.id}`)
})
b.addEventListener('click', (e) => {
const {
target,
currentTarget
} = e
console.log(`target是${target.id}`)
console.log(`currentTarget是${currentTarget.id}`)
})
c.addEventListener('click', (e) => {
const {
target,
currentTarget
} = e
console.log(`target是${target.id}`)
console.log(`currentTarget是${currentTarget.id}`)
})
d.addEventListener('click', (e) => {
const {
target,
currentTarget
} = e
console.log(`target是${target.id}`)
console.log(`currentTarget是${currentTarget.id}`)
})
想想输出的结果是什么?
addEventListener第三个参数不设置默认是冒泡顺序,当触发d时,呈现的结果如下
target是d currentTarget是d
target是d currentTarget是c
target是d currentTarget是b
target是d currentTarget是a
将addEventListener第三个参数设置为true,看看捕获阶段呢?
target是d currentTarget是a
target是d currentTarget是b
target是d currentTarget是c
target是d currentTarget是d
总结如下:
e.target
:触发事件的元素e.currentTarget
:绑定事件的元素
三 事件委托
通过上面的例子,我们可以很清晰的发现,如果当前父级元素下有若干个子级元素,对父级做监听后,当我们通过addEventListener回调函数返回的e.tartget
便能得到触发事件的元素.
<div id='list'>
<div id='item-1'>item-1</div>
<div id='item-2'>item-2</div>
<div id='item-3'>item-3</div>
<div id='item-4'>item-4</div>
</div>
通过给id为list的元素添加监听,在点击列表中的元素,便可实现事件委托,事件委托便是处理事件处理程序过多问题的一种解决方案
四 阻止事件流
阻止事件流常用的两种种方式
e.stopPropagation():阻止目标元素的事件冒泡到父级元素;
e.preventDefault():取消一个目标元素的默认行为(例如:a
链接,input
标签的submit
等)