在討論冒泡和捕獲之前,先看這么一段代碼:
<style>
.bd {
border: 1px solid #000;
padding: 8px;
}
</style>
<div id="container1" class="bd">
外層
<div id="container2" class="bd">
內(nèi)層
<div id="container3" class="bd">
最內(nèi)層
<div id="container4" class="bd">
按鈕
</div>
</div>
</div>
</div>
<script>
(() => {
const container1 = document.querySelector('#container1')
const container2 = document.querySelector('#container2')
const container3 = document.querySelector('#container3')
const container4 = document.querySelector('#container4')
container1.addEventListener('click', () => {
console.log('container1')
})
container2.addEventListener('click', () => {
console.log('container2')
})
container3.addEventListener('click', () => {
console.log('container3')
})
container4.addEventListener('click', () => {
console.log('container4')
})
})()
</script>
頁面渲染大概長(zhǎng)這樣:

點(diǎn)擊最里面的 按鈕
元素,按照思維慣例,是否應(yīng)該先執(zhí)行 container1
的點(diǎn)擊事件??畢竟 container1 是最外層,而且也是最先綁定事件的元素。
然而控制臺(tái)輸出結(jié)果為:
container4
container3
container2
container1
有點(diǎn)出乎意料是吧,為什么先執(zhí)行的是 container4
呢?
事件冒泡
JS 綁定的事件默認(rèn)是冒泡規(guī)則,什么意思呢?可以理解為:觸發(fā)事件后就像水里面有一個(gè)泡泡,在水底慢慢的往上冒,從觸發(fā)事件的目標(biāo)元素開始,經(jīng)過一層一層的盒模型,分別觸發(fā)盒模型身上綁定的事件。
所以上面代碼中,在點(diǎn)擊 按鈕
時(shí),先觸發(fā)了本身綁定的 click 事件,再一層一層往外傳播,最終就打印出了控制臺(tái)輸出的結(jié)果。
事件捕獲
注意:僅默認(rèn)狀態(tài)下,事件是冒泡規(guī)則,在綁定事件時(shí)候,可以修改第三個(gè)配置參數(shù)改為由外向內(nèi)傳播,這種傳播順序就是 事件捕獲
。
以上面代碼為藍(lán)本,僅添加 addEventListener 的第三個(gè)參數(shù)為 true,就將綁定規(guī)則改為了 事件捕獲
。如下:
container1.addEventListener('click', () => {
console.log('container1')
}, true)
container2.addEventListener('click', () => {
console.log('container2')
}, true)
container3.addEventListener('click', () => {
console.log('container3')
}, true)
container4.addEventListener('click', () => {
console.log('container4')
}, true)
還是點(diǎn)擊 按鈕
,上面代碼執(zhí)行結(jié)果:
container1
container2
container3
container4
事件捕獲還有另一種寫法,第三個(gè)參數(shù)可以傳入一個(gè)對(duì)象,通過對(duì)象的 capture
屬性設(shè)置為事件捕獲。
container1.addEventListener('click', () => {
console.log('container1')
}, {
capture: true,
})
冒泡與捕獲順序
既然同一個(gè)事件有冒泡與捕獲,那么冒泡與捕獲的順序如何?上例子:
container1.addEventListener('click', () => {
console.log('冒泡:', 'container1')
})
container2.addEventListener('click', () => {
console.log('冒泡:', 'container2')
})
container3.addEventListener('click', () => {
console.log('冒泡:', 'container3')
})
container4.addEventListener('click', () => {
console.log('冒泡:', 'container4')
})
container1.addEventListener('click', () => {
console.log('捕獲:', 'container1')
}, true)
container2.addEventListener('click', () => {
console.log('捕獲:', 'container2')
}, true)
container3.addEventListener('click', () => {
console.log('捕獲:', 'container3')
}, true)
container4.addEventListener('click', () => {
console.log('捕獲:', 'container4')
}, true)
同時(shí)給元素綁定兩種事件,點(diǎn)擊 按鈕
執(zhí)行結(jié)果:
捕獲: container1
捕獲: container2
捕獲: container3
捕獲: container4
冒泡: container4
冒泡: container3
冒泡: container2
冒泡: container1
到這里已經(jīng)可以得出結(jié)論:JS 的事件傳播會(huì)經(jīng)歷三個(gè)階段,由 事件捕獲
開始,傳遞到 目標(biāo)元素
之后,就改為 事件冒泡
,冒泡階段完了之后事件結(jié)束。
阻止事件傳播
既然事件有傳播,那程序就有辦法阻止事件傳播。所有事件執(zhí)行時(shí)都有一個(gè) event
對(duì)象,此對(duì)象中有方法可用于阻止事件傳播。
示例:
container1.addEventListener('click', () => {
console.log('冒泡:', 'container1')
})
container2.addEventListener('click', () => {
console.log('冒泡:', 'container2')
})
container3.addEventListener('click', () => {
console.log('冒泡:', 'container3')
})
container4.addEventListener('click', () => {
console.log('冒泡:', 'container4')
})
container1.addEventListener('click', (event) => {
event.stopPropagation()
console.log('捕獲:', 'container1')
}, true)
container2.addEventListener('click', () => {
console.log('捕獲:', 'container2')
}, true)
container3.addEventListener('click', () => {
console.log('捕獲:', 'container3')
}, true)
container4.addEventListener('click', () => {
console.log('捕獲:', 'container4')
}, true)
注意 event.stopPropagation()
這個(gè)方法,此方法是阻止事件傳播的關(guān)鍵。
以上代碼在 container1 這個(gè)元素上就阻止了事件傳播,所以點(diǎn)擊 按鈕
之后,僅 container1 會(huì)執(zhí)行,其他所有元素都不會(huì)再觸發(fā),結(jié)果:
捕獲: container1
調(diào)用 event.stopPropagation() 就是告訴 JS,事件到此為止,不再繼續(xù)了。
event 對(duì)象其他常用方法和屬性:
event.target:觸發(fā)事件的原始元素。
event.currentTarget:當(dāng)前綁定事件的元素(等同于 this)。
event.type:事件類型(如 "click")。
event.preventDefault():阻止默認(rèn)行為(如表單提交、鏈接跳轉(zhuǎn)、自定義右鍵菜單)。
event.stopPropagation():阻止事件冒泡。
event.stopImmediatePropagation():阻止同一元素的其他監(jiān)聽器執(zhí)行。
event.x 和 event.y:鼠標(biāo)點(diǎn)擊位置的坐標(biāo)。
在事件中要使用 this
獲取元素時(shí),必須使用 function 函數(shù),使用箭頭函數(shù)綁定的事件 this
將會(huì)指向外層作用域的 this 指針,如下代碼中箭頭函數(shù) this
指向的是 Window
:
<div id="container4" class="bd">
按鈕
</div>
<script>
(() => {
const container4 = document.querySelector('#container4')
container4.addEventListener('click', () => {
console.log(this)
})
container4.addEventListener('click', function () {
console.log(this)
})
})()
</script>
?轉(zhuǎn)自https://www.cnblogs.com/linx/p/18959113
該文章在 2025/7/3 9:00:46 編輯過