JS 冒泡和捕獲是怎麼回事 capture pop
看網上說的也不是太明白,我給重新整理下。
冒泡和捕獲是指在元素上的事件被觸發的時候,js 傳遞事件的兩種方向,或者說過程。
前言:
如,有這麼一個頁面 和 js 方法
scss: 我用 scss 寫的,如果沒有 scss 環境,可以無視這段。
.level {
padding: 50px 80px;
}
.level-template($level: 1, $color: #fff){
background-color: darken( $color , 5% * $level);
}
#lv1{ .level-template(1)}
#lv2{ .level-template(2)}
#lv3{ .level-template(3)}
HTML
<div id="lv1" class="level">
<div id="lv2" class="level">
<div id="lv3" class="level">
</div>
</div>
</div>
JS
function $(id) {
return document.getElementById(id);
}
window.onload = () => {
$('lv1').addEventListener("click",()=>{console.log('lv1')},true);
$('lv2').addEventListener("click",()=>{console.log('lv2')},true);
$('lv3').addEventListener("click",()=>{console.log('lv3')},true);
};
// 上面的 () => {} 為 ES6 的匿名方法的定義方式
// 等同于
function () {
console.log('lv1')
}
上面的 js 做的事:
在頁面載入的時候,給三個 div 添加 click 監聽方法,自己被點選的時候會在 console 中輸出自己的 id 值。
頁面的結構是這樣的
lv1
包含
lv2
,
lv2
又包含
lv3
,當點選
lv3
的時候,其實也點選了
lv2
和
lv1
,因為
lv3
在
lv2
内部,點選
lv3
的時候,自然也點選了
lv2
和
lv1
,也就是說,點選
lv3
的時候,會觸發三個
click
事件。
至于這三個事件觸發的順序,就是所謂的
冒泡
和
捕獲
。
事件觸發經過的三個階段:
- 捕獲階段:先由文檔的根節點
往事件觸發對象,從外向内捕獲事件對象;document
- 定位目标:尋找到目标事件位置(事發地),觸發事件;
- 冒泡階段:再從目标事件位置往文檔的根節點方向回溯,從内向外冒泡事件對象。
1. 捕獲階段
如上面的例子,在
lv3
被點選的時候,js 會從文檔的最上層開始,由外向内尋找點選事件的起源,也就是
lv3
。那麼這個由外向内的過程就是
lv1
-->
lv2
-->
lv3
,這三個 div 的 click 事件按照這個過程依次被觸發。
這個觸發的方向就是
捕獲
的方向。
2. 冒泡階段
在找到被點選的 lv3 之後,事件向上傳遞,過程是
lv3
-->
lv2
-->
lv1
,此時依次觸發
lv3
、
lv2
、
lv1
的
click
事件,這個由内向外的觸發過程就稱為
冒泡
再回看一下最常用的事件綁定方法的格式:
element.addEventListener(event, function, useCapture)
這裡面,
useCapture
是個布爾值,用于定義事件是在
冒泡階段
觸發,還是在
捕獲階段
觸發,預設值是
false
,代表在冒泡時觸發。
此時你就會知道上面那個例子裡定義的 click 方法是在
捕獲階段
執行,那麼傳回的結果就是
lv1
lv2
lv3
如果最上面的例子,
onload
内容是這樣的
window.onload = () => {
$('lv1').addEventListener("click",()=>{console.log('lv1')},false);
$('lv2').addEventListener("click",()=>{console.log('lv2')},false);
$('lv3').addEventListener("click",()=>{console.log('lv3')},false);
};
那麼也就是說,
click
事件在
冒泡階段
觸發,傳回的結果就是
lv3
lv2
lv1