事件冒泡 了解事件委託全流程

2022-07-16 14:54:16 字數 3648 閱讀 7508

說是初認識,其實也不算了,剛學習js時就已經聽過事件的冒泡和捕獲的大名,但真是不知所云,也是不求甚解,迷惑了很久,今天終決定好好來了解一下這個冒泡。

在此之前呢,不得不提一下事件流:描述的是從頁面中接受事件的順序。

當事件發生後,這個事件就要開始傳播(從裡到外或者從外向裡)。為什麼要傳播呢?因為事件源本身(可能)並沒有處理事件的能力,即處理事件的函式(方法)並未繫結在該事件源上。例如我們點選乙個按鈕時,就會產生乙個click事件,但這個按鈕本身可能不能處理這個事件,事件必須從這個按鈕傳播出去,從而到達能夠處理這個事件的**中(例如我們給按鈕的onclick屬性賦乙個函式的名字,就是讓這個函式去處理該按鈕的click事件),或者按鈕的父級繫結有事件函式,當該點選事件發生在按鈕上,按鈕本身並無處理事件函式,則傳播到父級去處理。

按我自己的理解,冒泡就真的是魚兒吐泡泡一樣,從水底冒乙個泡咕嚕咕嚕漂到了水面,這個順序是自下往上的;而捕獲呢,就像捕魚一樣從水面上撒網沉到水底,這個順序是自上往下的。這樣模擬到dom樹中應該就能夠記得很形象了。也就是說,事件冒泡 :當乙個元素接收到事件的時候,會把它接收到的事件傳給自己的父級,一直到window。

但有一點需要注意的,這裡傳遞的僅僅是事件,並不傳遞所繫結的事件函式。所以如果父級沒有繫結事件函式,就算傳遞了事件,也不會有什麼表現,但事件確實是傳遞了。我們用**來具體的表示,

html結構:

<

div

id="div1"

style

="width: 50px;height: 50px;background: red;"

>

2<

div

id="div2"

style

="width: 30px;height: 30px;background: blue;"

>

div>

3div

>

js部分:

var div1 = document.getelementbyid("div1");

2var div2 = document.getelementbyid("div2");

3 div2.onclick = function

()6 div1.onclick = function

()這段小**很簡單,定義了乙個父子關係的div元素,分別增加了點選事件。當我們點選子元素div2時,先會彈出它自身的事件「div2」,然後又彈出了「div1」。這就說明了點選子元素的時候不僅僅觸發了子元素自己的事件,它的父元素事件也被觸發 了。這樣的現象就叫做冒泡。

再舉個例子,還是剛剛的**,我們來做一些小修改,刪除子元素的點選事件!

可以看一下最終的效果圖,當點選子元素div2時,會彈出事件「div1」,這再次證明了觸發了冒泡模式,當點選了沒有繫結事件的子元素,父元素的點選事件被觸發,執行了自己繫結的函式。此外,這種事件的觸發,和css樣式是沒有關係的。可以改變父子元素的position位置,分離兩個元素的位置,這時仍會觸發冒泡。

當然,如果只刪除了父元素div1的點選事件,那點選子元素時只會觸發子元素的事件,而傳遞給父元素的只是事件,但因為父元素自身沒有繫結任何事件,就算傳遞給它事件,父元素仍然無法觸發事件。

至此,我們算是初認識了事件冒泡,會不會感覺這沒什麼用呀,其實冒泡真有一大優點,就是產生了事件委託。所謂事件委託:

事件委託: 由於事件的冒泡,我們點選子元素的時候,會把事件一層層的傳遞給父級元素。相反的,我們操作元素的時候,直接把事件繫結在父級元素上,而不是分別給子元素繫結事件。通過判斷子元素,從而達到同樣的效果

先上例子,假設情形:有5個列表,我們點選其中乙個就會改變其背景顏色為紅色。

html結構很簡單:

<

ul id

="ul"

>

2<

li>這就是個測試

li>

3<

li>這就是個測試

li>

4<

li>這就是個測試

li>

5<

li>這就是個測試

li>

6<

li>這就是個測試

li>7ul

>

js部分:

var ul = document.getelementbyid("ul");

2var li = ul.getelementsbytagname("li");

3for(var i=0; i)

7 }通過迴圈給每乙個 li 加事件,感覺應該也沒什麼問題,但其實這是非常耗費效能的。就算不考慮效能吧,那就假設乙個很極端的情況,如果我想在第6個位置新增乙個div元素,第7個位置新增乙個p元素,同樣的內容要實現同樣的效果,那是不是就需要另外給這個div和p分別新增乙個點選事假,這就很麻煩了。

如果我們可以給父元素ul新增事件,作用於全部子元素,那不是一勞永逸嘛,而這個就是通過冒泡模式進行的事件委託實現的。但是這就會有個問題,我選中的是ul,那麼點選其中的任一 li 時,豈不是全部的 ul 列表都變紅了嘛,這與初始需求相違背了。這就需要新概念的登場了,能夠準確獲取你當前滑鼠所指的 li 的事件源。

事件源:不管事件繫結在那個元素中,都指的是實際觸發事件的那個的目標

這也存在ie的相容性問題:

那麼做一下相容性處理,js部分變為:

var ul = document.getelementbyid("ul");

2var li = ul.getelementsbytagname("li");

34 ul.onclick = function

(ev)

這樣就很好的提高了效能,而且在增加其他子元素時候,同樣可以滿足需求。

但是喲,冒泡模式也存在一些困擾,譬如假設乙個情形:

需求是,點選div1時候,能夠讓div2顯示,再點選其他地方時會讓div2隱藏。那js可以這樣寫: 

var div1 = document.getelementbyid("div1");

2var div2 = document.getelementbyid("div2");

34 div1.onclick = function

()7 document.onclick = function

()去瀏覽器驗證最終效果,很神奇的發現點選了紅色部分,藍色方塊消失了!明明是需要讓它顯示的嘛,看一下我們寫的**,邏輯很簡單直白,完全無懈可擊呀。

這就是冒泡惹的禍,由於事件冒泡,點選div1時候,事件向上傳遞,一直傳到了document,而此時的document也繫結了自己的事件,那就正好觸發了,也就是讓藍色方塊隱藏了。所以,也不能說點選紅色方塊沒有讓藍色方塊顯示,而是這個過程太短暫 了,還沒顯示呢就已經觸發了最終的document的事件。可以在div1事件中新增乙個彈框用來測試是否進行了這一步驟。

因此,這種情況下我們就不希望存在冒泡了,那就需要用到取消事件的冒泡的兩種方式:

因為這存在ie和其他瀏覽器的差異,所以會做乙個判斷,封裝成乙個函式:

function

stopbubble(e)

首先,判斷這個瀏覽器是否支援stoppropagation(),如果支援說明是非ie,可以使用標準的w3c方式,不然就是用ie提供的辦法。有了這樣乙個阻止冒泡的函式,那就在div1事件中呼叫這個函式,讓我們點選div1時不會再往上冒泡傳遞事件,也就不會觸發到document的事件了,這樣當初的需求完美實現了。

參照委託理解事件

namespace eventdemo public static void listen bark 1 純委託型別版 事件 不安全 class dog public delebark onbark dog的委託型別成員 事件 2 私有委託型別的 事件 安全可控 onbark定義為private 的...

事件冒泡和事件委託

今天學到了事件冒泡和事件委託這兩個詞,現在談一下我的理解。如果有錯誤,還望各位大佬及時糾正,謝謝。事件冒泡 父元素和子元素有觸發事件時,如果子元素觸發,會引起父元素事件也觸發。有一點搞清楚,父元素通常就相當於是乙個大盒子,而子元素則是裡面的內容。解決辦法 有時候,不需要觸發父元素的時候,可以使用ev...

事件冒泡 事件捕獲和事件委託

事件冒泡會從當前觸發的事件目標一級一級往上傳遞,依次觸發,直到document為止。事件捕獲會從document開始觸發,一級一級往下傳遞,依次觸發,直到真正事件目標為止。事件委託依靠的就是事件冒泡和事件捕獲的機制。box1 box2 box3 上面是三個具有父子關係的box,分別繫結了列印事件,現...