1. 程式人生 > >深入理解JavaScript事件冒泡

深入理解JavaScript事件冒泡

一、什麼是事件冒泡

在一個物件上觸發某類事件(比如單擊onclick事件),如果此物件定義了此事件的處理程式,那麼此事件就會呼叫這個處理程式,如果沒有定義此事件處理程式或者事件返回true,那麼這個事件會向這個物件的父級物件傳播,從裡到外,直至它被處理(父級物件所有同類事件都將被啟用),或者它到達了物件層次的最頂層,即document物件(有些瀏覽器是window)。

打個比方說:你在地方法院要上訴一件案子,如果地方沒有處理此類案件的法院,地方相關部門會幫你繼續往上級法院上訴,比如從市級到省級,直至到中央法院,最終使你的案件得以處理。

二、事件冒泡有什麼作用

(1)事件冒泡允許多個操作被集中處理

(把事件處理器新增到一個父級元素上,避免把事件處理器新增到多個子級元素上),它還可以讓你在物件層的不同級別捕獲事件

【集中處理例子】

複製程式碼 <div onclick="eventHandle(event)" id="outSide" style="width:100px; height:100px; background:#000; padding:50px"><div id="inSide" style="width:100px; height:100px; background:#CCC"></div></div><script type="text/javascript"
>//本例子只在外面盒子定義了處理方法,而這個方法一樣可以捕獲到子元素點選行為並處理它。假設有成千上萬子元素要處理,難道我們要為每個元素加“onclick="eventHandle(event)"”?顯然沒有這種集中處理的方法來的簡單,同時它的效能也是更高的。function eventHandle(e)
{
    
var e=e||window.event;
    
var obj=e.target||e.srcElement;
    alert(obj.id
+' was click')
}
</script> 複製程式碼

(2)讓不同的物件同時捕獲同一事件,並呼叫自己的專屬處理程式做自己的事情,就像老闆一下命令,各自員工做自己崗位上的工作去了。

【同時捕獲同一事件例子】

複製程式碼 <div onclick="outSideWork()" id="outSide" style="width:100px; height:100px; background:#000; padding:50px"><div onclick="inSideWork()" id="inSide" style="width:100px; height:100px; background:#CCC"></div></div><script type="text/javascript">function outSideWork()
{
    alert(
'My name is outSide,I was working...');
}

function inSideWork()
{
    alert(
'My name is inSide,I was working...');
}

//因為下面程式自動啟用單擊事件,有些瀏覽器不允許,所以請單擊灰色盒子,從這裡開始下命令,這樣因為冒泡的原因,黑色大盒子也會收到單擊事件,並呼叫了自己的處理程式。如果還有更多盒子巢狀,一樣道理。/*
function bossOrder()
{
    document.getElmentById('inSide').click();
}
bossOrder();
*/</script> 複製程式碼

三、需要注意什麼

●事件捕獲其實有三種方式,事件冒泡只是其中的一種:(1)IE從裡到外(inside→outside)的冒泡型事件。(2)Netscape4.0從外到裡(outside→inside)的捕獲型事件。(3)DOM事件流,先從外到裡,再從裡到外回到原點(outside→inside→outside)的事件捕獲方法(似乎物件將觸發兩次事件處理,這有什麼作用?鄙人不懂!)。

●不是所有的事件都能冒泡。以下事件不冒泡:blur、focus、load、unload。

●事件捕獲方式在不同瀏覽器,甚至同種瀏覽器的不同版本中是有所區別的。如Netscape4.0採用捕獲型事件解決方案,其它多數瀏覽器則支援冒泡型事件解決方案,另外DOM事件流還支援文字節點事件冒泡。

●事件捕獲到達頂層的目標在不同瀏覽器或不同瀏覽器版本也是有區別的。在IE6中HTML是接收事件冒泡的,另外大部分瀏覽器將冒泡延續到window物件,即……body→documen→window。

●阻止冒泡並不能阻止物件預設行為。比如submit按鈕被點選後會提交表單資料,這種行為無須我們寫程式定製。

四、阻止事件冒泡

通常情況下我們都是一步到位,明確自己的事件觸發源,並不希望瀏覽器自作聰明、漫無目的地去幫我們找合適的事件處理程式,即我們明確最精準目標,這種情況下我們不需要事件冒泡。另外通過對事件冒泡的理解,我們知道程式將做多較多額外的事情,這必然增大程式開銷。還有一個重要的問題是:事件冒泡處理可能會啟用我們本來不想啟用的事件,導致程式錯亂,甚至無從下手除錯,這常成為對事件冒泡不熟悉程式設計師的棘手問題。所以必要時,我們要阻止事件冒泡。

【不想啟用的事件被啟用例子】

複製程式碼 <div onclick="openWin('http://www.baidu.com')" id="outSide" style="width:100px; height:100px; background:#000; padding:50px"><div onclick="openWin('http://www.google.com')" id="inSide" style="width:100px; height:100px; background:#CCC"></div></div><script type="text/javascript">//本例你實際希望點選灰色盒子開啟google首頁,而點選黑色盒子開啟baidu首頁,但結果你點選灰色盒子的時候,卻是同時打開了兩個網頁。其實在實際設計中較少遇到此問題,你可能會想如果我在頁面不同DOM深處安置了不同的按鈕或連結,深層處的事件觸發會不會波及頂層的按鈕呢?不會,因為按鈕不能形成巢狀關係。function openWin(url)
{
    window.open(url);
}
</script> 複製程式碼

下面是本人在網上抄的一個方法,把這個方法放在精準目標物件處理程式結尾,本事件觸發處理結束後,事件將不在進行冒泡處理。

【阻止事件冒泡例子】

複製程式碼 <div onclick="showMsg(this,event)" id="outSide" style="width:100px; height:100px; background:#000; padding:50px"><div onclick="showMsg(this,event)" id="inSide" style="width:100px; height:100px; background:#CCC"></div></div><script type="text/javascript">//阻止事件冒泡後,你點選灰色盒子,整個過程只彈一次對話方塊了(注意與預設情況對比)function showMsg(obj,e)
{
    alert(obj.id);
    stopBubble(e)
}

//阻止事件冒泡函式function stopBubble(e)
{
    
if (e && e.stopPropagation)
        e.stopPropagation()
    
else
        window.event.cancelBubble
=true
}
</script> 複製程式碼