1、事件階段
如下圖所示
一般的,事件分為三個階段:捕獲階段、目標階段和冒泡階段。
(1)捕獲階段(Capture Phase)
事件的第一個階段是捕獲階段。事件從文檔的根節點流向目標對象節點。途中經過各個層次的DOM節點,并在各節點上觸發捕獲事件,直到到達事件的目標節點。捕獲階段的主要任務是建立傳播路徑,在冒泡階段,事件會通過這個路徑回溯到文檔跟節點。
(2)目標階段(Target Phase)
當事件到達目標節點的,事件就進入了目標階段。事件在目標節點上被觸發,然后會逆向回流,直到傳播至最外層的文檔節點。
(3)冒泡階段(Bubble Phase)
事件在目標元素上觸發后,并不在這個元素上終止。它會隨著DOM樹一層層向上冒泡,回溯到根節點。
冒泡過程非常有用。它將我們從對特定元素的事件監聽中釋放出來,如果沒有事件冒泡,我們需要監聽很多不同的元素來確保捕獲到想要的事件。
2、冒泡階段調用事件處理函數
封裝一個getTag函數,當點擊a標簽的時候,由于是冒泡機制,會從目標節點向上逐級觸發各個節點a,li,ul,div的事件處理函數。
3、捕獲階段調用事件處理函數
在function回調函數里加個true,則為事件捕獲。當點擊a標簽的時候,由于是捕獲機制,會從根節點向下逐級觸發各個節點直到目標節點觸發事件處理函數即div,ul,li,a
4、事件代理
在傳統的事件處理中,你按照需要為每一個元素添加或者是刪除事件處理器。然而,事件處理器將有可能導致內存泄露或者是性能下降——你用得越多這種風險就越大。JavaScript事件代理可以把事件處理器添加到一個父元素上,這樣就避免了把事件處理器添加到多個子元素上。
(1)它是怎么運作的呢?
事件代理用到了兩個JavaSciprt事件特性:事件冒泡以及目標元素。當一個元素上的事件被觸發的時候,同樣的事件將會在那個元素的所有祖先元素中被觸發。這一過程被稱為事件冒泡;使用事件代理,我們可以把事件處理器添加到一個元素上,等待一個事件從它的子級元素里冒泡上來,并且可以得知這個事件是從哪個元素開始的。
(2)這對我有什么好處呢?
比如說在一個10列、100行的HTML表格里,讓其每一個單元格在被點擊的時候變成可編輯狀態。如果把事件處理器加到這1000個單元格會產生一個很大的性能問題,并且有可能導致內存泄露甚至是瀏覽器的崩潰。相反地,使用事件代理,你只需要把一個事件處理器添加到table元素上就可以了,這個函數可以把點擊事件給截下來,并且判斷出是哪個單元格被點擊了。
(3)另一個簡單的例子
如圖所示,如果我們需要對每個li元素進行點擊,觸發事件。傳統的我們要像綠色注釋部分那樣給每一個li元素添加事件處理函數。但是通過事件代理,我們只需要在ul元素進行事件監聽就可以實現點擊每一個li都能觸發事件了
5、阻止事件冒泡(stopPropagation)
(1)為什么要阻止事件冒泡
有種可能是,某個DOM節點綁定了某事件監聽器,本來是想當該DOM節點觸發事件,才會執行回調函數。結果是該節點的某后代節點觸發某事件,由于事件冒泡,該DOM節點事件也會觸發,執行了回調函數,這樣就違背了最初的本意了。
(2)如何阻止事件冒泡
如圖所示,在第一個li標簽加上event.stopPropagation()方法就能阻止事件的冒泡,這樣的話在點擊第一個li標簽就無法觸發事件處理函數了。
(3)無法在捕獲階段阻止事件冒泡
這里需要注意的是,我們無法在事件捕獲階段阻止事件冒泡!!!例如,我們在代碼里加上true,如圖所示,第一個li會觸發事件。因為捕獲是從根節點向目標節點觸發,而冒泡是從目標節點向根節點觸發。