开篇
stopImmediatePropagation
与stopPropagation
是一对亲兄弟,他们两实现的功能是相似的,那么这两个函数的区别在哪里呢?如果你对于事件传播已经很了解,那么可以直接跳到总结部分,反之可以按照顺序阅读。
什么是DOM事件流?
早上起床你都会做些什么呢?闹钟响了,你摸索着掐掉闹钟,再眯一会,然后起床,刷牙,吃早餐…,这一系列事件连接起来就构成了你起床的事件流。而DOM事件也是有一个流程的,DOM 事件标准描述了事件传播的 3 个阶段:
- 捕获阶段(Capturing phase)—— 事件(从 Window)向下走近元素。
- 目标阶段(Target phase)—— 事件到达目标元素。
- 冒泡阶段(Bubbling phase)—— 事件从元素上开始冒泡。
事件捕获
DOM事件触发时(被触发DOM事件的这个元素被叫作事件源),浏览器会从根节点开始 由外到内 进行事件传播。即事件从文档的根节点流向目标对象节点,途中经过各个层次的DOM节点,最终到目标节点,完成事件捕获,
事件冒泡
事件冒泡与事件捕获顺序相反。事件捕获的顺序是从外到内,事件冒泡是从内到外。
当事件传播到了目标阶段后,处于目标阶段的元素就会将接收到的时间向上传播,就是顺着事件捕获的路径,反着传播一次,逐级的向上传播到该元素的祖先元素,直到window对象。
引发事件的那个嵌套层级最深的元素被称为目标元素,可以通过
event.target
访问。注意与this
(=event.currentTarget
)之间的区别:
event.target
—— 是引发事件的“目标”元素,它在冒泡过程中不会发生变化。this
—— 是“当前”元素,其中有一个当前正在运行的处理程序。
使用addEventListener监听事件
使用EventTarget.addEventListeners
可以指定的侦听器注册到EventTarget上,我们可以监听页面上发生的诸多事件(mousedown
,click
, scroll
等),当事件发生时就可以调用相应的函数进行事件处理。
它接收三个参数:分别是type
, listener
, options
, 其中type
表示监听事件类型的字符串,listener
通常传入的是一个函数,在相应事件发生时调用它进行事件处理,options
是一个与listener
有关的可选参数对象,可用的参数有capture
,once
,passive
, signal
,
在本文中比较关注的是capture
, 默认为false
, 代表该侦听器在时间冒泡阶段触发,反之在事件捕获阶段触发。
如何阻止事件传播?
很经典的一个问题是如何阻止事件冒泡,很多人应该马上就能想到使用event.cancleBuble = true
或者使用event.stopPropagation()
, 这的确能够阻止事件冒泡。其实更准确的说,应该是阻止了事件传播, 因为这两者不仅仅可以在冒泡阶段使用,也可以在捕获阶段使用。看下面这一个例子。
Event.cancelBubble
属性是Event.stopPropagation()
的一个曾用名。在从事件处理程序返回之前将其值设置为true可阻止事件的传播。
dom结构如下:
<div class="A" style="font-size:30px">
A
<div class="B" style="font-size:30px">
B
<p style="font-size:30px