事件冒泡 和 事件捕獲
背景知識
什麼是事件?
直觀的說就是網頁上發生的事情,大部分是指使用者的滑鼠動作和鍵盤動作,如點選、移動滑鼠、按下某個鍵。為什麼說大部分呢,因為事件不單單隻有這兩部分,還有其他的例如document的load和unloaded。只不過我們更加關注的是使用者的操作。
事件模型:規範事件的定義的一種標準
事件的三種模型:
- 原始事件模型(DOM 0級事件模型)
- IE事件模型
- DOM2事件模型
DOM2事件模型:
此模型是W3C制定的標準模型,既然是標準,那大家都得按這個來,我們現在使用的現代瀏覽器(指IE6~8除外的瀏覽器)都已經遵循這個規範。W3C制定的事件模型中,“DOM2級事件”中規定的事件流同時支援了事件捕獲階段和事件冒泡階段,而作為開發者,我們可以選擇事件處理函式在哪一個階段被呼叫。
一次事件的發生包含三個過程:
(1)capturing phase:事件捕獲階段。
事件被從document一直向下傳播到目標元素,在這過程中依次檢查經過的節點是否註冊了該事件的監聽函式,若有則執行。
(2)target phase:事件處理階段。
事件到達目標元素,執行目標元素的事件處理函式.
(3)bubbling phase:事件冒泡階段。
事件從目標元素上升一直到達document,同樣依次檢查經過的節點是否註冊了該事件的監聽函式,有則執行。
所有的事件型別都會經歷captruing phase(事件捕獲),但是隻有部分事件會經歷bubbling phase(事件冒泡)階段,例如submit事件就不會被冒泡。
1. 是什麼?
<div id="outer">
<p id="inner">Click me!</p>
</div>
上面的程式碼當中一個div元素當中有一個p子元素,如果兩個元素都有一個click的處理函式,那麼我們怎麼才能知道哪一個函式會首先被觸發呢?
為了解決這個問題微軟和網景提出了兩種幾乎完全相反的概念。
**事件流 : ** 指的是頁面中接收事件的順序.
事件冒泡
微軟提出了名為事件冒泡(event bubbling)的事件流。
事件冒泡可以形象地比喻為把一顆石頭投入水中,泡泡會一直從水底冒出水面。
當一個DOM元素上的事件被觸發的時候(如:按鈕點選事件),這個元素的所有父元素 中,如果也繫結有該相同事件,則也會被觸發, 觸發的順序就是先從 : 當前元素的事件 ==> 臨近父元素 ==> 父元素......,這一過程被稱為事件冒泡
因此上面的例子在事件冒泡的概念下發生click事件的順序應該是:
p -> div -> body -> html -> document
IE,火狐和chrome瀏覽器都是事件冒泡.
事件捕獲
網景提出另一種事件流名為事件捕獲(event capturing)。
當一個DOM元素上的事件被觸發的時候(如:按鈕點選事件),這個元素的所有父元素 中,如果也繫結有該相同事件,則也會被觸發, 觸發的順序就是先從 : ....... 父元素 ==> 臨近父元素 ==> 當前元素的事件,這一過程被稱為事件捕獲
與事件冒泡相反,事件會從最外層開始發生,直到最具體的元素。
上面的例子在事件捕獲的概念下發生click事件的順序應該是:
document -> html -> body -> div -> p
圖解:
2. 解決了什麼問題?
這兩個概念都是為了解決頁面中事件流(事件發生順序)的問題。
http://www.imooc.com/article/9833
3. 執行原理
<ul>
<li>
<p>
<a> </div>
</p>
</li>
</ul>
事件捕獲階段:事件從最上一級標籤開始往下查詢,直到捕獲到事件目標(target)。
事件冒泡階段:事件從事件目標(target)開始,往上冒泡直到頁面的最上一級標籤。
事件捕獲當你使用事件捕獲時,父級元素先觸發,子級元素後觸發,即div先觸發,p後觸發。
事件冒泡當你使用事件冒泡時,子級元素先觸發,父級元素後觸發,即p先觸發,div後觸發。
4. 如何使用?
說到事件的執行順序,那麼我們需要知道一個給元素新增事件的方法, 即給某元素動態繫結事件
W3C為我們提供了addEventListener()函式用來為指定的dom元素動態繫結事件。
語法:
element.addEventListener( event , function , useCapture )
提示: 使用 removeEventListener()方法來移除 addEventListener() 方法新增的事件控制程式碼。
function sayHello() {
console.log("hello");
}
var myDiv = document.getElementById("myDiv");
myDiv.addEventListener("click", sayHello);
這樣我們點選id為myDiv的元素時,控制檯就會輸出"Hello"。
事件冒泡
有如下html程式碼:
下面設定了四個函式用來進行事件繫結:
使用下面的程式碼,我們可以獲取四個元素對應DOM
現在,我試著同時分別為grandpa和grandson繫結sleep和doingHomework事件:
這時我們點選最外層的grandpa時,當然會觸發sleep函式,然而當我們點選grandson時,控制檯的輸出如下:
原因:這是因為grandson在grandpa之上,當點選grandson時,同時也在grandpa上進行了點選操作,所以在執行了doingHomework後,還會觸發grandpa的sleep函式。
這種當滿足條件後從子元素到父元素依次觸發其上事件的處理方式叫做事件冒泡
我們也為father和child分別繫結watchTV和playingCard函式
事件冒泡()
grandpa.addEventListener("click", sleep);
grandson.addEventListener("click", doingHomework);
father.addEventListener("click", watchTV);
child.addEventListener("click", playingCard);
事件捕獲
事件捕獲與事件冒泡完全相反,先觸發祖先元素的事件,然後再逐級觸發子元素的事件。預設情況下,繫結事件時,採用事件冒泡原則,如果想要進行事件捕獲的話,需要設定一個引數 。
可以為addEventListener函式新增第三個引數useCapture,引數值是布林值,預設是false。當useCapture為false時,事件處理採取事件冒泡的原則,當userCapture為true時,則採取事件捕獲的原則
這時,當點選grandson時,就會先執行祖先元素的事件,再執行後代元素的事件了,控制檯的輸出如下圖所示:
雖然預設情況下,useCapture的值是false,但我推薦我們在繫結函式時把它明顯的寫出來以避免瀏覽器相容性的問題。
事件冒泡與事件捕獲要是同時進行怎麼辦
有思想的同學肯定會思考這樣一個問題,在上述繫結事件的程式碼中,第三個引數不是全部設定的true,就是全部設定成false,那如果既有true,又有false,有的元素設定成按事件冒泡處理,有的元素設定成按事件捕獲處理,那怎麼辦呢?
直接告訴大家答案,我們的瀏覽器更“喜愛”事件捕獲:
它會先把useCapture為false的元素繫結事件放到一邊,按照事件捕獲正常的順序執行useCapture為true的元素繫結事件,最後在按照事件冒泡順序執行useCapture為false。
現在我們作如下更改
按照上述原則,當點選grandson時,先執行useCapture為true的元素的繫結事件,又按照事件捕獲原則,先執行grandpa的事件,再執行child的事件。之後,再按照事件捕獲順序執行useCapture為false的事件,輸出結果如下:
阻止事件冒泡和捕獲
我們可以利用時間物件event的stopPropagation()
方法阻止事件的進一步傳播。
我們修改一下doingHomework函式:
發現事件執行到doingHomework就被阻斷了,其後不會在事件傳播到父元素。
值得注意的是,event.stopPropagation()函式並不會阻止其下函式內容的執行。
*如果你使用的是jquery的事件繫結,也可以直接在函式中使用return false來阻止事件的傳播(當然event.stopPropagation同樣有效),與event.stopPropagation不同的是,return false會阻止同函式下面的程式碼執行 *
傳統繫結事件方式在一個支援W3C DOM的瀏覽器中,像這樣一般的繫結事件方式,是採用的事件冒泡方式。ele.onclick = doSomething2
IE瀏覽器
如上面所說,IE只支援事件冒泡,不支援事件捕獲,它也不支援addEventListener函式,不會用第三個引數來表示是冒泡還是捕獲,它提供了另一個函式attachEvent。ele.attachEvent("onclick", doSomething2);
不是所有的事件都能冒泡,例如:blur、focus、load、unload。
事件冒泡的好處
相關文章
- 關於js事件冒泡和事件捕獲JS事件
- 理解js的事件冒泡和事件捕獲JS事件
- JavaScript事件捕獲冒泡與捕獲JavaScript事件
- 事件的捕獲、冒泡、委託事件
- JS中的事件順序(事件捕獲與冒泡)JS事件
- Javascript中的事件冒泡與捕獲JavaScript事件
- Spirit帶你徹底瞭解事件捕獲和冒泡機制事件
- JavaScript 事件捕獲JavaScript事件
- JavaScript 事件冒泡JavaScript事件
- 事件的冒泡事件
- 關於瀏覽器裡事件的捕獲和冒泡及監聽器執行的順序瀏覽器事件
- javascript事件捕獲是什麼意思JavaScript事件
- stopPropagation() 阻止事件冒泡事件
- JavaScript阻止事件冒泡JavaScript事件
- 事件溯源模式:分離事件的發生和捕獲兩種不同時間 - verraes事件模式
- 阻止捕獲和冒泡,阻止預設行為
- zepto繫結事件改變冒泡事件流事件
- JQuery6:事件冒泡jQuery事件
- 在DOM上同時繫結兩個點選事件(一個用捕獲,一個用冒泡),事件總共會執行幾次,先執行哪個事件?事件
- 原生js如何阻止事件冒泡JS事件
- JavaScript和JQuery的滑鼠mouse事件冒泡處理JavaScriptjQuery事件
- #每日一記#通過 GIF 理解 addEventListener、捕獲和冒泡dev
- Vue事件獲取觸發事件物件和繫結事件物件Vue事件物件
- 使用嵌入式Debezium和SpringBoot捕獲更改資料事件(CDC) - Sohan GanapathySpring Boot事件
- 梳理下常見的不冒泡事件事件
- JavaScript 阻止事件冒泡程式碼例項JavaScript事件
- vue的事件冒泡 最詳細解釋版本Vue事件
- React 事件和 Dom 事件React事件
- onscroll 事件和onScrollCapture事件事件APT
- cocos2d-js:遊戲進入後臺和返回遊戲的事件捕獲和處理JS遊戲事件
- 獲取LOV事件事件
- 【Android ViewPager】解決ViewPager使用DepthPageTransformer時事件會被下一頁捕獲導致事件錯亂的問題AndroidViewpagerORM事件
- WPF雙滑塊控制元件以及強制捕獲滑鼠事件焦點控制元件事件
- 前端學習程式碼例項-JavaScript阻止事件冒泡前端JavaScript事件
- 事件和事件監聽器事件
- 事件模型和事件委託事件模型
- 事件溯源的好處在於可在軟體中捕獲現實世界 – Jessitron事件
- jQuery學習筆記02--讀取和操作屬性,讀取和操作屬性節點,新增、刪除、改變類,操作html、css、value,操作事件,事件冒泡及阻止事件冒泡,預設行為及阻止預設行為,自動觸發事件jQuery筆記HTMLCSS事件
- jquery獲取回車事件jQuery事件