記錄addEventListener的相關知識
1、addEventListener的引數 有三個引數:第一個引數表示事件名稱(不包括on,比如“click”);第二個引數表示要接收事件處理的函式,第三個引數為useCapture
記錄一下第三個引數,有兩種方式,可以設定成Boolean型別(useCapture)或者Object型別(options)
當第三個引數時Object型別時,
- options包括三個布林值選項:
1、capture:預設false,是否使用時間捕獲,也就是使用事件冒泡;
2、once:預設值為false,是否只調用一次,如果是true,會在呼叫後自動銷燬listener;
3、passive:如果是true,意味著listener永遠不會呼叫preventDefault方法,如果又確實呼叫了的話,
瀏覽器只會console一個warning,而不會真的去執行preventDefault方法。根據規定預設值是false,
但是chrome,FireFox等瀏覽器為了保證滾動時的效能,在document-level nodes(Window,
Document,Document.body)上針對touchstart和touchmove事件,將passive預設值改為了true,
保證了在頁面滾動時不會因為自定義事件呼叫了preventDefault而阻塞頁面渲染。
- useCapture:預設值為false(即,使用事件冒泡)
當第三個引數時Boolean型別的值,事件(event)在事件目標(eventTarget)中的順序 - Capturing 捕獲
- Bubbling 冒泡
Capturing就是從上往下
1 | | 2 ---------------| |----------------- 3 | element1 | | | 4 | -----------| |----------- | 5 | |element2 \ / | | 6 | ------------------------- | 7 | Event CAPTURING | 8-----------------------------------
這種情況下,事件發生後,註冊在element1上的handler(事件)會先觸發,註冊在element2上的handler會後觸發。
Bubbling就是從下往上:
1 / \ 2 ---------------| |----------------- 3 | element1 | | | 4 | -----------| |----------- | 5 | |element2 | | | | 6 | ------------------------- | 7 | Event BUBBLING | 8 -----------------------------------
這種情況下,事件發生後,註冊在element2上的handler會先觸發,註冊在element1上的handler會後觸發。
W3C標準中的事件順序
1 | | / \ 2 -----------------| |--| |----------------- 3 | element1 | | | | | 4 | -------------| |--| |----------- | 5 | |element2 \ / | | | | 6 | -------------------------------- | 7 | W3C event model | 8 ------------------------------------------
在W3C模型中,事件會先從上往下,到事件目標元素後,再從下往上,一直到最外面的元素。
程式碼示例
1 <div id="parent">parent div 2 <div id="child">child div</div> 3 </div>
1 const parent = document.querySelector('#parent'); 2 const child = document.querySelector('#child'); 3 4 function first() { 5 alert('first'); 6 } 7 function second() { 8 alert('second'); 9 } 10 11 parent.addEventListener('click', second, false); 12 child.addEventListener('click', first);
點選child元素,會先彈出first,然後彈出second。為什麼會有這樣呢?
click事件再child元素髮生之後,第一步是capturing階段,先從上往下尋找child元素的錨定元素中是否有可以觸發的handler,如果useCapture是true的話就會再此階段觸發,結果發現沒有可觸發的handler。
click事件到達child元素後觸發first方法,然後開始bubbling階段,到達parent元素時發現有用於此階段的handler,觸發second方法。
如果把程式碼改成下面的樣子
1 parent.addEventListener('click', second, true); 2 child.addEventListener('click', first);
點選child元素,會先彈出second,然後彈出first。分析過程如下:
click事件再child元素髮生後,第一步是capturing階段,先從上往下尋找child元素的錨定元素(Ancestor Element)中是否有可以觸發的handler,發現可以觸發second。
click事件到達child元素後觸發first方法,然後開始bubbling階段,到達parent元素時發現有用於此階段的handler,沒有發現可以觸發的handler。
為了避免出現記憶體洩漏問題,可以用removeEventlister來清除掉eventListener。
關於JavaScript捕獲和冒泡移步這位大佬的文章: