一、是捕獲還是冒泡
昨天被問到一個問題:事件流有幾個階段?在這幾個階段中,事件一共發生幾次?
問題很簡單,但事件總共發生幾次有點亂。總覺得捕獲也能觸發事件、冒泡也能觸發事件,可事件確實只發生了一回啊!所以寫篇文章梳理一下,對此很清楚的同學可以跳過了。
子問題1:事件流有幾個階段?
「DOM2級事件」規定的事件流包含三個階段:事件擷取階段、處於目標階段、事件冒泡階段。
1. IE9以前的IE瀏覽器都只支援後兩個階段,也就是處於目標階段和事件冒泡階段。這個順序很好理解,在巢狀層次最深的節點上接收事件,然後逐級向上傳播到父級節點。
2. 早期的Netscape團隊提出的另一個事件流叫做事件擷取。即頂層節點應該更早的接收事件,逐步傳播到嵌套層次最深的節點,也就是事件捕獲階段和處於目標階段
3. 現代瀏覽器如chrome、ff、IE9等支援整個三個階段。
子問題2:在這幾個階段中,事件一共發生幾次?
事件發生時,「DOM2級事件」的事件流都會經歷三個階段(捕獲->處於目標->冒泡),但不是每個階段都能發生事件。對於某個節點,addEventListener方法第三個參數如果為true,則事件發生在捕獲階段;如果為false,則事件發生在冒泡階段。所以事件只發生了一次!
如果外層節點想在捕獲和冒泡階段都發生事件,那就註冊兩次吧。
附帶一句,「DOM0級事件」(elem.onclick = function () {…})也是存在事件冒泡的。
二、事件的註冊順序
在同一節點上註冊多個事件,
使用addEventListener,發生先後順序依據事件新增的順序;過來的,後註冊的先發生。
三、移除事件
移除事件的方法removeEventListener與detachEvent針對事件發生時的同一個回呼函數,所以註冊事件時使用匿名函數的情況是不能被移除的。