event flow (Dow)
阿新 • • 發佈:2018-11-11
哪怕一個web開發的初學者都會知道,當我們滑鼠在button上點選時,會在button上觸發一個click事件。但是:
- button是div的一個子Node;從介面上來看,在button裡點選相當於在div裡點選;那click事件也會觸發在div上嗎?
- 如果click事件也觸發在div上,那它們會不會共用同一個事件物件?
- 如果click事件也觸發在div上,誰的事件會先發生?
- click事件還會在哪些元素上面觸發?
- 等等...
想解答上述問題,我們需要理解事件(Event)一個很重要的機制:事件流動(Event Flow)。
事件流動
"eventPhase"
“eventPhase”是“Event”下的一個屬性,它指明當前event屬於那一個階段。
“eventPhase”可能是一下其中一個值:
- Event.NONE,0,沒有事件需要處理
- Event.CAPTURING_PHASE,1,捕獲階段
- Event.AT_TARGET,2,目標階段,事件物件到達事件目標上
- Event.BUBBLING_PHASE,3,冒泡階段
捕獲階段(capture phase)
捕獲階段發生在整個事件流動的開始。在這階段裡事件會從父(主幹)到子(分支)由上往下傳播,被元素一層層地捕獲。
文章開頭的例子裡面,捕獲階段的click事件會依次在document、body、div上觸發:
addEventListener
的第三個引數設定為true:
// 第三個引數設定是否為捕獲階段,預設為false
element.addEventListener('click', function() {}, true)
目標階段(target phase)
例子裡面,就是事件在button上觸發的。addEventListener
可以監聽目標階段的事件:
element.addEventListener('click', function() {})
如果事件是不可冒泡的,那整個事件流動會到此為止,不會發生下面的冒泡階段。
冒泡階段(bubble phase)
冒泡階段發生在最後,這也是我們最為熟悉的一個階段。在這階段裡事件會從子(分支)到父(主幹)逆向傳播,看起來像是一個水裡的泡泡往上冒。
例子裡面,冒泡階段的click事件會依次在div、body、document上觸發:
總結
若一個元素(div)是目標元素(button)的祖先,那事件物件會在該元素上觸發兩次:一次是捕獲階段(1)的,另一次是冒泡階段(3)的。當事件物件在事件目標元素(button)上觸發時,事件流動進入了目標階段(2)。
- 想監聽捕獲階段的事件,可以這樣:
element.addEventListener('click', cb, true)
,將第三個引數設定為true。 - 想監聽冒泡階段的事件,可以這樣:
element.addEventListener('click', cb,)
,不使用第三個引數或將其設定為false。 - 而上述的任何一種監聽方式都可以監聽到目標階段的事件。