今天要學習的部分是關於 DOM 的傳遞機制:捕捉與氣泡
在切入今日的主題之前,先快速了解一下 addEventListener
的語法。
addEventListener
透過這個語法,我們可以將事件綁定在某個 HTML 元素上,並透過觸發的條件(如滑鼠點擊、按下鍵盤某一個按鍵等)進而得到需求的資訊並執行我們設定的行為。
target.addEventListener(type, listener[, options]);
type
: 表示要觸發的方式,例如 click
、 keydown
等。listener
: 會是一個函式,用於當條件觸發時需要做的任務options
: 條件觸發時決定是在捕捉或氣泡階段執行。預設為 false
,此時表示於氣泡階段執行; true
則為捕捉階段。來看看 addEventListener
的測試例子:
<style>
.box{
width:100px;
height:100px;
background:#ccc;
}
</style>
<div class="box"></div>
const box = document.querySelector('.box');
box.addEventListener('click',test,true);
function test(e){
console.log(e)
}
上述就是一個透過 addEventListener
語法而設計的監聽事件,被監聽的對象是 <div>
元素,觸發條件為 click
(滑鼠點擊時才觸發),而作為監聽事件的 test
函式,會傳入一個 e
的參數,這個參數用於接收當事件被觸發時,可以獲得的對應訊息。
接下來要進入主題,關於捕捉與氣泡的規範可以到 w3c event-flow 詳讀,有著更詳細的圖例。
而這裡為了搭配測試例子,所以簡化了 DOM 的結構。
先直接來看圖,並透過圖貫穿後續的篇幅:
上圖為接下來程式碼的 DOM 結構,並標示出了捕捉與氣泡階段的位置,再來來看看測試例子:
<style>
.container {
width: 500px;
height: 100px;
background: #aaaadd;
}
.text {
background: #cccccc;
}
</style>
<div class="container">
container area
<p class="text">Lorem ipsum dolor sit amet.</p>
</div>
const container = document.querySelector('.container');
const text = document.querySelector('.text');
container.addEventListener('click', test, true);
function test(e) {
console.log('點擊到的元素為: container');
}
text.addEventListener('click', test2, true);
function test2(e) {
console.log('點擊到的元素為: text');
}
HTML 畫面如下:
container
與 text
皆設定參數為false
,當點擊 text
時:text
在 container
,所以會得到如圖的結果。container
與 text
皆設定參數為true
,當點擊 text
時:container
在 text
,所以會得到如圖的結果。container
參數為true
而 text
參數為false
,當點擊 text
時:container
在捕捉階段執行而 text
在氣泡階段執行。所以執行順序為先 container
在 text
,所以會得到如圖的結果。container
參數為false
而 text
參數為true
,當點擊 text
時:container
在氣泡階段執行而 text
在捕捉階段執行。所以執行順序為先 text
在 container
,所以會得到如圖的結果。e.stopPropagation
因為傳遞機制,所以在點擊 text
元素時,也會因此讓 container
也在這個過程中觸發行為。
但如果不想要這樣子的話,就必須使用 e.stopPropagation()
e.stopPropagation()
可以阻止當前事件捕捉與冒泡的傳遞,如此就不會在這個過程中同時也觸發到其他元素。
所以來將測試例子改寫一下:
const container = document.querySelector('.container');
const text = document.querySelector('.text');
container.addEventListener('click', test, true);
function test(e) {
console.log('點擊到的元素為: container');
}
text.addEventListener('click', test2, true);
function test2(e) {
e.stopPropagation();
console.log('點擊到的元素為: text');
}
當點擊 text
元素時,因為 e.stopPropagation()
會終止事件傳遞,所以可以得到如圖結果。
e.preventDefault
最後是如何取消元素自有的預設行為,舉例來說,當點擊 html 的 <a>
標籤時,會直接導向設定的連結。
但有時候我們會希望先經過一些處理後才導向某個網址,這個時候就需要用到 e.preventDefault()
了。
透過 e.preventDefault
可以將 HTML 的 <a>
標籤點擊後自動導向的默認行為取消,來看看測試例子
<a href ="http://www.google.com" class="link">This is a link</a>
const link = document.querySelector('.link');
link.addEventListener('click',test);
function test(e){
e.preventDefault();
console.log(e);
}
可以嘗試將 e.preventDefault()
註解並看看差異性。
今天就到這裡囉~
明天見~