要理解事件冒泡機制,就得先了解事件。
瀏覽器是事件驅動型的,根據用戶的行為觸發不同的事件,根據事件執行相應的操作。我們較為熟悉的事件有三大類型:鼠標鍵盤事件、頁面事件、表單相關事件。
鼠標鍵盤事件:onclick、ondbclick、onmousedown、onmouseup、onmouseover、onmousemove、onmouseout、onkeypress、onkeydown、onkeyup;
頁面事件:onload、onunload、onresize、onerror、onabort;
表單相關事件:onblur、onchange、onfocus、onreset、onsubmit。
需要注意的是事件處理程序中的變量event保留着事件對象的信息,包括比如click事件,事件屬性里有點擊位置相對於瀏覽器,以及頁面的坐標信息,事件的類型(click),觸發事件的DOM節點信息等。
什么是事件冒泡?
DOM中,樹狀結構決定了子元素肯定在父元素里,所以點擊子元素,就同時點擊了子元素和父元素,以及父元素的父元素,以此類推,當然最終的根節點都是文檔,以及window。
試想,當一個子元素被點擊的時候,不僅僅這個元素本身被點擊了,因為這個元素也在其上一級父元素中(屬於父級元素的地盤),所以相當於其父元素也被點擊了,以此類推,一層一層往外推,最終整個文檔也是被點擊了,如果每個層級的節點元素都綁定了click事件,那么每個節點的click事件函數都會被執行。舉個形象的例子,一個村里的人被打了(click),首先就要按照村里的規矩處理,同時這個村屬於某個鄉鎮,當然也是相當於這個鄉鎮的人被打了,那么也要按照這個鄉鎮的規矩處理,以此一層一層往上報。這個例子不准確的地方就是,現實中一個人因為一個事件只會被處理一次,不會因為同一件事情多次處理。
冒泡帶來的煩惱
當上層(以及上上層,直至body元素)父級有子元素同樣的方法,但你子元素的事件后,所有父級元素的同名函數也會從下到上,由里往外,挨個執行,但是大多數情況下,我們只希望子當事元素事件執行,不希望層層執行,這就要想辦法阻止這種冒泡的情況發生。比如我們點擊Child Span的時候只顯示 Child Span的內容。結合剛剛的例子就是,村里發生了打人事件,在村里解決了,就沒必要一層一層往上報,在層層處理了。
阻止事件冒泡的方法:
1 阻止事件繼續往上層傳遞的過程
利用事件的stopPropagation()函數終止往父級元素冒泡的過程。
注意 該方法具有兼容性的問題,Event.stopPropagation()在支持W3C的瀏覽器中使用沒有問題,但是在IE瀏覽器就失效了,在IE中使用 Event.cancelBubble=true來代替:
if (Event.stopPropagation){
Event.stopPropagation(); }else{
Event.cancelBubble=true;
}
注:而在vue中,則通過.stop阻止,例如:<div @click.stop='click1'></div>
2 通過事件委托,不阻止冒泡過程,但是讓事件在冒泡到指定節點時再觸發,不再是層層觸發
這種方法同樣不阻止事件的冒泡過程,同時也不在冒泡過程的各元素執行方法上添加判斷,而是在冒泡過程中的某個父節點,對其所有下屬的節點事件進行判斷,然后執行相應的操作。
注意這個冒泡過程的最終節點,不一定要到body,到文檔,到window,可以是冒泡過程中的任一一個終止冒泡的節點,所以我們可以在這個節點上,對其所有子元素的冒泡事件進行判斷和處理。
這種元素本身觸發事件,但是事件執行的方法不在元素本身,而是在其父元素的某個節點上,這種“模式叫做事件委托。