這次是介紹事件捕捉、事件冒泡、停止冒泡、事件監聽。當你很清楚這些事件的時候,開發時就比較不會踩雷,然後卻不知道為什麼會這樣。其實概念不困難,實際看範例就懂了~
個人codepen
以下是html結構
<div class="one">
one
<div class="two">
two
<div class="three">three</div>
</div>
</div>
再來是監聽點擊事件
const divs = document.querySelectorAll("div");
function logTxt(e) {
console.log(this.classList.value);
}
divs.forEach((item) => item.addEventListener("click", logTxt));
上面的監聽點擊,預設是冒泡行為,當你點擊最內層的three時,會依序觸發three、two、one,由內往外觸發點擊事件。
那如果你只希望事件停留在最內層three的時候,就要加上stopPropagation()。如下,點擊事件就不會向上傳遞,只停留在three。
function logTxt(e) {
e.stopPropagation();
console.log(this.classList.value);
}
同樣的html結構
<div class="one">
one
<div class="two">
two
<div class="three">three</div>
</div>
</div>
於綁定監聽事件時,設定事件捕捉。
const divs = document.querySelectorAll("div");
function logTxt(e) {
e.stopPropagation();
console.log(this.classList.value);
}
divs.forEach((item) => item.addEventListener("click", logTxt, true));
跟Bubbling事件冒泡差別就在於addEventListener的第三個參數true。第三個參數本身沒有代入時,就預設是false,因此可省略。你要改成事件捕捉,就要設定第三個參數為true。
此時當你點擊three的時候,點擊事件會從最外層的one開始向內傳遞。會依序log出one、two、three的文字。
第三個參數為一個物件,可以代入幾個值,capture、once、passive等...
divs.forEach((item) => item.addEventListener("click", logTxt, {
once: true,
}));
divs.forEach((item) => item.addEventListener("click", logTxt, {
once: true,
capture: true,
}));
如果你只需要用事件捕捉,不需要用once的話,就可以簡潔的直接帶入true。
divs.forEach((item) => item.addEventListener("click", logTxt, true));
<form action="">
<button>submit</button>
</form>
const button = document.querySelector("button");
button.addEventListener('click', (e) => {
e.preventDefault();
console.log("submit!!!");
})
如果今天設置了passive為true,即使你寫了preventDefault也不會有作用。原生預設的form事件還是會發生。而且控制台會報錯,
button.addEventListener('click', (e) => {
e.preventDefault();
console.log("submit!!!");
}, {
passive: true,
})
MDN文件中,有提到某一些的事件,像是wheel、mousewheel、touchstart 、touchmove,本身的passive就是true。讓瀏覽器的預設行為可以繼續進行,以提高性能。
因為瀏覽器在不確定你是否要執行preventDefault的狀況下,會有延遲來等待結果,進而造成畫面有點卡頓。目前,瀏覽器的預設passive都是true。
重新看了一次MDN文件,發現真的寫很詳細,而且連範例都有。不過你如果切換成中文版的,會發現資料變超少。所以只能乖乖看英文,看不懂就去翻譯。難怪人家都說要看原文文件。不然資料都掉一半...