1. 程式人生 > 其它 >記錄addEventListener的相關知識

記錄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)中的順序
    當DOM元素之間存在包含關係時,發生在元素上的事件有兩種順序。
  • 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捕獲和冒泡移步這位大佬的文章:

JavaScript捕獲和冒泡探討http://caibaojian.com/javascript-capture-bubble.html