JS 30 是由加拿大的全端工程師 Wes Bos 免費提供的 JavaScript 簡單應用課程,課程主打 No Frameworks
、No Compilers
、No Libraries
、No Boilerplate
在30天的30部教學影片裡,建立30個JavaScript的有趣小東西。
另外,Wes Bos 也很無私地在 Github 上公開了所有 JS 30 課程的程式碼,有興趣的話可以去 fork 或下載。
瞭解addEventListener
中事件的捕捉、傳遞(Event Bubbling/Capturing
)以及一次性的事件監聽(Once
)。
建立三層的div
做為測試event listener
的物件。
div(.one
) : 淡紫色
div(.two
) : 淡粉色
div(.three
) : 橘色
<div class="one">
<div class="two">
<div class="three">
</div>
</div>
</div>
首先取得所有的div
標籤,然後在每個div
上都註冊cllick event listener
並以logText()
進行事件處理把div
標籤的class
屬性值印出來。
const divs = document.querySelectorAll('div');
function logText(e){
console.log(this.classList.value);
}
divs.forEach(div => div.addEventListener('click',logText));
點擊最內層的div
(橘色),console 印出的內容如下 :
由上面的結果,我們可以得知在 div(.three
)捕捉到事件後,還會連帶向上觸發parents
的event handler
,這種由底部向上傳遞觸發event handler
的機制稱為event bubbling
。
傳遞順序 : div.three(橘色) -> div.two(淡粉色) -> div.one(淡紫色)
前面的Event Bubbling
是從觸發事件的element
開始向外層的parent element
進行事件傳遞,而Event Capturing
則是從觸發事件的element
的最外層parent element
向內進行傳遞。
要做到這一點,我們就必須使用到addEvenListener
的第三個參數Options Object
的capture
屬性,這個屬性的預設值是false
,我們只需要把它改成true
即可。
/*上略...*/
divs.forEach(div => div.addEventListener('click',logText,{
capture: true
}));
設定完後點擊div.three
,console 印出結果如下 :
傳遞順序 : div.one(淡紫色) -> div.two(淡粉色) -> div.three(橘色)
capture
: true,Event Capturing
。capture
: false,Event Bubbling
。
上方的Event Bubbling
其實可被改寫如下 :
/*上略...*/
divs.forEach(div => div.addEventListener('click',logText,{
capture: false //預設就是 false 可直接省略
}));
那如果不想讓事件由內向外(bubbling
)或由外向內(capturing
)傳遞要怎麼辦呢? 我們可以在event handler
裡面對Event
呼叫stopPropagation()
,讓事件不再繼續傳遞。
以阻止Event Bubbling
為例,在event handler
裡面,我們對event(e)
呼叫stopPropagation()
。
/*上略...*/
function logText(e){
console.log(this.classList.value);
e.stopPropagation(); //stop bubbling or capturing
}
divs.forEach(div => div.addEventListener('click',logText,{
capture: false
}));
然後點擊div.three
,console 印出結果如下 :
由上可知呼叫stopPropagation()
後,事件就沒有繼續傳遞。
addEvenListener
的第三個參數Options Object
的屬性除了capture
之外,還有once
這個屬性(預設是false),它可以用來指定是否在觸發一次事件處理後,就unbind event listener
(讓事件監聽器失效)。
下面以按鈕作為例子 :
在網頁上放置一個button
。
<button>Button</button>
透過 JS 取得button
標籤,然後為其註冊click event listener
並指定Options Object
的once
屬性為 true。
const button = document.querySelector('button');
const text = '努力は自分に裏切らない、梦想は裏切ります!努力は梦を実现することはできない!しかし、努力している事実は自分を慰めることができる。--大先生'
button.addEventListener('click',() => alert(text),{
once: true
});
此時點擊button
,視窗會顯示提示訊息,但若在未 reload 頁面的情況下二次點擊button
,會發現視窗不再顯示提示訊息,也就是button
失效了。
這個效果可以放在提交表單的按鈕上,用來防止使用者重複提交表單。
EventTarget.addEventListener()
Event.stopPropagation()
[教學] 瀏覽器事件:Event Bubbling, Event Capturing 及 Event Delegation