前言
上圖是W3C標準的DOM事件流模型圖,從圖中可以看出,元素事件響應在DOM樹中是從頂層的Window開始“流向”目標元素,然後又從目標元素“流向”頂層的Window
通常,我們將這種事件流向分為三個階段:
捕獲階段,目標階段,冒泡階段
1。捕獲階段是指事件響應從最外層的Window開始,逐級向內層前進,直到具體事件目標元素。在捕獲階段,不會處理響應元素註冊的冒泡事件。
2。目標階段指觸發事件的最底層的元素,如上圖中的。
3。冒泡階段與捕獲階段相反,事件的響應是從最底層開始一層一層往外傳遞到最外層的Window。
現在,我們就可以知道,DOM事件流的三個階段是
先捕獲階段,然後是目標階段,最後才是冒泡階段
。我們時常面試所說的先捕獲後冒泡也由此而來。
事件代理就是利用事件冒泡或事件捕獲的機制把一系列的內層元素事件繫結到外層元素
事件冒泡和事件捕獲
實際操作中,我們可以透過 element。addEventListener() 設定一個元素的事件模型為冒泡事件或者捕獲事件。
先來看一下 addEventListener 函式的語法:
element。addEventListener(type, listener, useCapture)// type 監聽事件型別的字串// listener 事件監聽回撥函式,即事件觸發後要處理的函式// useCapture 預設值false,表示事件冒泡;設為true時,表示事件捕獲
事件冒泡舉例
冒泡事件的執行順序為:c -> b -> a
事件捕獲舉例
捕獲事件的執行順序為:a -> b -> c
事件捕獲VS事件冒泡
我們將上述的程式碼a,b,c三個元素都註冊捕獲和冒泡事件,並以元素c作為觸發事件的主體,即事件流中的目標階段。
執行順序為:
捕獲a
->
捕獲
b ->
冒泡
c ->
捕獲c
->
冒泡
b ->
冒泡
a
從執行結果可以看到,a,b兩個元素的事件響應都是先捕獲後冒泡的,但對於觸發事件的目標元素c,事件的響應並沒有遵循先捕獲後冒泡的規則,這是為什麼?因為
目標元素是事件觸發主體處於事件流中的目標階段,處理事件的順序是根據註冊順序來執行的
。
事件代理(事件委託)
我們知道了事件冒泡和事件捕獲的原理,那麼對於事件委託就比較容易理解了。
重複一遍,事件代理就是利用事件冒泡或事件捕獲的機制把一系列的內層元素事件繫結到外層元素。至於為什麼通常我們說事件代理是利用事件冒泡的機制來實現的,只是大家習以為常而已。
//div
- item1
- item2
- item3
- item4
對於上述的列表元素,我們希望將使用者點選了哪個item打印出來,通常我們可以給每個item註冊點選事件監聽器,但是需要對每個元素進行事件監聽器的註冊;但是透過事件代理,我們可以將多個事件監聽器減少為一個,這樣就減少程式碼的重複編寫了。
利用事件冒泡或事件捕獲實現事件代理
事件代理既可以透過事件冒泡來實現,也可以透過事件捕獲來實現
。
總結
DOM事件流有3個階段:捕獲階段,目標階段,冒泡階段;三個階段的順序為:捕獲階段——目標階段——冒泡階段;
對於非目標階段的元素,事件響應執行順序遵循先捕獲後冒泡的原則;透過暫緩執行捕獲事件,可以達到先冒泡後捕獲的效果;
對於目標元素,事件響應執行順序根據的事件的執行順序執行;
事件捕獲是從頂層的Window逐層向內執行,事件冒泡則相反;
事件委託(事件代理)是根據事件冒泡或事件捕獲的機制來實現的。