1. 程式人生 > >10th WEEK BLOG2:envent flow事件流動

10th WEEK BLOG2:envent flow事件流動

DOM事件不單單隻會在一個Element上觸發,它還會流向其他Element。事件的流動通常會經歷這麼三個階段:

捕獲階段 -> 目標階段 -> 冒泡階段

"eventPhase"

“eventPhase”是“Event”下的一個屬性,它指明當前event屬於那一個階段。
“eventPhase”可能是一下其中一個值:

  • Event.NONE,0,沒有事件需要處理
  • Event.CAPTURING_PHASE,1,捕獲階段
  • Event.AT_TARGET,2,目標階段,事件物件到達事件目標上
  • Event.BUBBLING_PHASE,3,冒泡階段

下面我們詳細討論一下這三個階段。

捕獲階段(capture phase)

捕獲階段的定義如下(w3c):

The event object propagate through the target's ancestors from the defaultView to the target's parent.
事件物件在事件目標的祖先中上到下順向傳播,從最頂層的defaultView到事件目標的(直系)父元素。

捕獲階段發生在整個事件流動的開始。在這階段裡事件會從父(主幹)到子(分支)由上往下傳播,被元素一層層地捕獲。
文章開頭的例子裡面,捕獲階段的click事件會依次在document、body、div上觸發:

document    1
  v
body    2
  v
div    3
  v
button

一般我們沒太大需要監聽捕獲階段的事件;如果你確實希望這麼做,需要將addEventListener的第三個引數設定為true:

// 第三個引數設定是否為捕獲階段,預設為false
element.addEventListener('click', function() {}, true)

目標階段(target phase)

目標階段的定義是(w3c):

The event object arrive at the event object's event target.
事件物件到達事件目標。

例子裡面,就是事件在button上觸發的。addEventListener可以監聽目標階段的事件:

element.addEventListener('click', function() {})

如果事件是不可冒泡的,那整個事件流動會到此為止,不會發生下面的冒泡階段。

冒泡階段(bubble phase)

冒泡階段的定義如下(w3c):

The event object propagates through the target's ancestors in reverse order, starting with the target's parent and ending with the defaultView.
事件物件會在事件目標的祖先元素裡反向傳播,由開始的父元素到最後的defaultView(document)。

冒泡階段發生在最後,這也是我們最為熟悉的一個階段。在這階段裡事件會從子(分支)到父(主幹)逆向傳播,看起來像是一個水裡的泡泡往上冒。
例子裡面,冒泡階段的click事件會依次在div、body、document上觸發:

document    3
  ^
body    2
  ^
div    1
  ^
button

"bubbles"

Event下的bubbles屬性標明該事件是否為可冒泡的。一旦該值為false,則說明 evnet不可冒泡,那其流動也會在第二階段“目標階段”後就終止。


總結

若一個元素(div)是目標元素(button)的祖先,那事件物件會在該元素上觸發兩次:一次是捕獲階段(1)的,另一次是冒泡階段(3)的。當事件物件在事件目標元素(button)上觸發時,事件流動進入了目標階段(2)。

  • 想監聽捕獲階段的事件,可以這樣:element.addEventListener('click', cb, true),將第三個引數設定為true。
  • 想監聽冒泡階段的事件,可以這樣:element.addEventListener('click', cb,),不使用第三個引數或將其設定為false。
  • 而上述的任何一種監聽方式都可以監聽到目標階段的事件。

Example

      let divElement = document.querySelector('div')
      let btnElement = document.querySelector('button')
      
      document.body.addEventListener('click', event => {
        console.log('Body Click in Bubble Phase.')
        console.log('Event Phase: ' + event.eventPhase)
      })
      
      document.body.addEventListener('click', event => {
        console.log('Body Click in Capture Phase.')
        console.log('Event Phase: ' + event.eventPhase)
      }, true)

      divElement.addEventListener('click', event => {
        console.log('Div Click in Bubble Phase.')
        console.log('Event Phase: ' + event.eventPhase)
      })
      
      divElement.addEventListener('click', event => {
        console.log('Div Click in Capture Phase.')
        console.log('Event Phase: ' + event.eventPhase)
      }, true)
      
      btnElement.addEventListener('click', event => {
        console.log('Button Click in Target Phase.')
        console.log('Event Phase: ' + event.eventPhase)
      })
      
      btnElement.addEventListener('click', event => {
        console.log('Button Click in Target Phase.')
        console.log('Event Phase: ' + event.eventPhase)
      }, true)
Body Click in Capture Phase.
Event Phase: 1
Div Click in Capture Phase.
Event Phase: 1
Button Click in Target Phase.
Event Phase: 2
Button Click in Target Phase.
Event Phase: 2
Div Click in Bubble Phase.
Event Phase: 3
Body Click in Bubble Phase.
Event Phase: 3

 

Javascript事件:事件監聽器

DOM Level 2 Events定義了兩個用於分配和刪除事件處理程式的方法:addEventListeners()和removeEventListeners()

這些方法存在於所有DOM節點上並接受三個引數:要處理的事件的名稱,事件處理函式和用於表示是否呼叫事件處理程式的布林值,即truefalse

事件偵聽器具有類似於事件處理程式的功能,區別在於將多個功能分配給同一DOM元素和事件時處理程式沒有限制。