iT邦幫忙

2019 iT 邦幫忙鐵人賽

DAY 25
1
Modern Web

一起挑戰 JavaScript 30 吧!系列 第 25

JS30 Day 25 - Event Capture, Propagation, Bubbling and Once

  • 分享至 

  • xImage
  •  

展示頁面(請打開 console 查看結果)程式碼

今天沒有要做作品,而是認識一下 DOM 元素的 event bubbling & event capturing

Event Bubbling

Event Bubbling 也就是冒泡事件,這也是事件監聽的預設方式(另一種是 Event Capturing,等等會介紹)

從 HTML 可以看到共有三個區塊元素,div.one 在最外面,依序包覆 div.two 以及 div.three,如果將三個元素都設定監聽事件並點擊最裡面的 div.three 並印出 this.classList.value,你覺得結果會是什麼?

function logText() {
    console.log(this.classList.value);
}

div.forEach(div => div.addEventListener('click', logText));

// 點擊 div.three 後
// three
// two
// one

結果 threetwoone 依序被印出,而這就是 Event Bubbling;會有這轉現象產生是因為當最裡面的 three 被點擊時,會如同漣漪一般由內至外擴散到父層容器,並一路直達最外層(也就是 body,但由於 body 沒有設定監聽事件,所以不會看到 console 印出來)

Event Capturing

相對於 bubbling 是由內至外,capturing 則是由外至內的發生,但首先我們要先設定 capturing

設定的方式有兩種,一種是在監聽事件的第三個參數帶入 true(而 false 就是 bubbling 了!)

div.forEach(div => div.addEventListener('click', logText, true));

另一種方法是在第三個參數帶入一個 object,並指定屬性 capture: true

div.forEach(div => div.addEventListener('click', logText, {capture: true}));

這時再點擊 three,會發現觸發順序變了!

// 點擊 three 後
// one
// two
// three

變成由最外層先被觸發了而不是剛剛的最內層 three,這就是 Event Capturing

簡單來說 bubbling 就是由內而外,而 capturing 則是由外至內

避免 bubbling & capturing 的發生

如果要避免 bubbling & capturing 的發生,可以在 callback 中寫入 event.stopPropagation(),禁止 bubbling 或是 capturing 的發生

function logText(e) {
    e.stopPropagation();
    console.log(this.classList.value);
}

div.forEach(div => div.addEventListener('click', logText));

現在點擊時,只會看到當前點擊的元素了,而不會 bubblng 至父層;而當設定 capturing 時,每次點擊都會是 one,這也是因為禁止 capturing,所以觸發事件只會在最外層發生

once:只監聽一次的事件

最後要介紹的是 once,一個可以放在監聽事件中的屬性。它的功能是只會監聽一次事件,當觸發並執行 callback 後就不再被觸發,可以想成是事件觸發一次後執行 removeEventListener(..) 的感覺

這裡的範例是 HTML 最下方的元素 button,我們加入 once 屬性

button.addEventListener('click', logText, {capture: false, once: true});

當點擊按鈕時,只有第一次會印出 button,之後不管你按得多猛烈都不會有效果

今天介紹就到這裡,謝謝收看!

Reference


上一篇
JS30 Day 24 - Sticky Nav
下一篇
JS30 Day 26 - Stripe Follow Along Nav
系列文
一起挑戰 JavaScript 30 吧!30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言