一个事件发生后,会在子元素和父元素之间传播。这种传播分成三个阶段。
-
第一阶段:从
window
对象传导到目标节点(上层传到底层),称为“捕获阶段”(capture)。 -
第二阶段:在目标节点上触发,称为“目标阶段”(target)。
-
第三阶段:从目标节点传导回
window
对象(从底层传回上层),称为“冒泡阶段”(bubble)。
这种三阶段的传播模型,使得同一个事件会在多个节点上触发。
首先看下面代码:
<div>
<h1>点击</h1>
</div>
const phases = {
1: 'capture',
2: 'target',
3: 'bubble'
}
const div = document.querySelector('div')
const h = document.querySelector('h1')
div.addEventListener('click', callback, true)
h.addEventListener('click', callback, true)
div.addEventListener('click', callback, false)
h.addEventListener('click', callback, false)
function callback(event) {
const tag = event.currentTarget.tagName
const phase = phases[event.eventPhase]
console.log("Tag: '" + tag + "'. EventPhase: '" + phase + "'")
}
打印结果为:
Tag: 'DIV'. EventPhase: 'capture'
Tag: 'H1'. EventPhase: 'target'
Tag: 'H1'. EventPhase: 'target'
Tag: 'DIV'. EventPhase: 'bubble'
上述代码中,点击事件被触发了四次,h1触发了两次,先触发捕获,再触发冒泡,也验证了上述事件传播的的顺序(捕获->目标->冒泡)。
事件传播的最上层对象是window
,接着依次是document
,html
(document.documentElement
)和body
(document.body
)。上述的事件传播顺序,在捕获阶段依次为window
、document
、html
、body
、div
、h1
,在冒泡阶段依次为h1
、div
、body
、html
、document
、window
。
stopPropagation
方法只会阻止事件的传播,而不会阻止该事件触发<h1>
元素的其他click
事件的监听函数。也就是说,不是彻底取消click
事件。如果想要彻底取消该事件,不再触发后面所有click
的监听函数,可以使用stopImmediatePropagation
方法。
对于事件目标上的事件监听器来说,事件会处于“目标阶段”,而不是冒泡阶段或者捕获阶段。捕获阶段的事件监听器会在任何非捕获阶段的事件监听器之前被调用。
addEventListener()
用于定义一个特定事件的监听函数。一旦这个事件发生,就会执行监听函数。该方法没有返回值。该方法有三个参数:
-
type
:事件名称,大小写敏感。 -
listener
:监听函数。事件发生时,会调用该监听函数。 -
useCapture
:布尔值,表示监听函数是否在捕获阶段(capture)触发,默认为false
(监听函数只在冒泡阶段被触发)。该参数可选。