js事件流機制冒泡和捕獲
JavaScript與HTML之間的互動是通過事件實現的。事件,就是文件或瀏覽器視窗中發生的一些特定的互動瞬間。
事件流
從頁面中接收事件的順序稱為事件流。
IE --> 事件冒泡流
Netscape --> 事件捕獲流
事件冒泡
IE的事件流叫做事件冒泡(event bubbling),即事件開始時由最具體的元素(文件中巢狀層次最深的那個節點)接收,然後逐級向上傳播到較為不具體的節點(文件)。
我們先來個簡單的例子,這是HTML結構
<!DOCTYPE html> <html lang="en"> <head> <title>js事件流</title> </head> <body> <div id="div"> 我是div </div> </body> </html>
有一個div元素。如果我們點選<div>
元素,那麼這個click事件的順序會怎麼呢?
我們給幾個元素都新增監聽事件,
element.addEventListener(event, function, useCapture)
引數說明:
- event 字串。指定事件名,比如 click、mouseenter、mouseleave
- function 函式。指定要事件觸發時執行的函式。
- useCapture 布林值。指定事件是否在捕獲或冒泡階段執行。預設值是false,即事件在冒泡階段執行。true,在捕獲階段執行
var div = document.getElementById('div') var body = document.body var html = document.documentElement div.addEventListener('click', function () { console.log('div標籤') }, false) body.addEventListener('click', function () { console.log('body ') }, false) html.addEventListener('click', function () { console.log('html') }, false) document.addEventListener('click', function () { console.log('document') }, false)
然後點選<div>
元素,檢視控制檯輸出,
由上面的輸出結果可以看出,這個click事件會按照如下順序傳播:
<div>
---> <body>
---> <html>
--->document
也就是說,click事件首先發生在目標元素,然後,click事件沿著DOM樹向上傳播到document物件。這就是事件冒泡。
所有現代瀏覽器都支援事件冒泡。IE9、Firefox、Chrome和Safari則將事件一直冒泡到window物件。
如果,我們在每個DOM元素上都設定監聽事件,會得到的事件的傳播順序是:
<div>
<body>
---> <html>
--->document
---> window
事件捕獲
Netscape Communicator團隊提出的另一種事件流叫做事件捕獲(event capturing)。事件捕獲是不太具體的節點應該更早接收到事件,而最具體的節點應該最後接收到事件。事件捕獲的用意在於在事件到達預期目標之前捕獲它。
我們還是可以看剛才的例子,DOM結構不變,我們修改下監聽事件
var div = document.getElementById('div')
var body = document.body
var html = document.documentElement
div.addEventListener('click', function () {
console.log('div標籤')
}, true)
body.addEventListener('click', function () {
console.log('body ')
}, true)
html.addEventListener('click', function () {
console.log('html')
}, true)
document.addEventListener('click', function () {
console.log('document')
}, true)
之後,還是點選<div>
元素,得到的結果
從上面例子可以看出,事件走向: document
---><html>
---> <body>
---><div>
也就是說,在事件捕獲過程中,document物件首先接收到click事件,然後事件沿著DOM樹依次向下,一直傳播到事件的實際目標,即
<div>
元素。這就是事件捕獲。與事件冒泡過程,截然相反。
儘管“DOM2級事件”規範要求事件應該從document物件開始傳播,但是現代瀏覽器大部分都是從window物件開始捕獲事件的。
如果,我們在每個DOM元素上都設定監聽事件,會得到的事件的傳播順序是:
window
---> document
---><html>
---> <body>
---><div>
由於在老版本的瀏覽器中不支援,因此事件捕獲用的人比較少,除非在特殊需要的時候才使用。
DOM事件流
“DOM2級事件”規定的事件流包括三個階段:事件捕獲階段、處於目標階段和事件冒泡階段。
首先發生的是事件捕獲,為截獲事件提供了機會。然後是實際的目標接收到事件。最後一個階段是冒泡階段,可以在這個階段對事件作出響應。

事件捕獲階段:在DOM事件流中,實際的目標(
<div>
元素)在捕獲階段不會接收到事件。這意味著在捕獲階段,事件從document到<html>
再到<body>
後就停止了。處於目標階段:事件在
<div>
上發生,並在事件處理中被看成冒泡階段的一部分。事件冒泡階段:冒泡階段發生,事件又傳播迴文檔。
雖然,“DOM2級事件”規範明確要求捕獲階段不會涉及事件目標,但是IE9及以上的現代瀏覽器都會在捕獲階段觸發事件目標物件上的事件。結果,就是有兩個機會在目標物件上面操作事件,也就是說上圖中的步驟4,既可以在捕獲階段發生,也可以在冒泡階段發生。
IE8級更早版本不支援DOM事件流,現代瀏覽器都支援DOM事件流。
事件流的應用
事件流比較典型應用是事件委託。事件委託利用了事件冒泡,只指定一個事件處理程式,就可以管理一型別的所有事件。
我們檢視一個常用例子,這是一個無序列表的DOM結構:
<ul>
<li id="li1">我是第1個li</li>
<li id="li2">我是第2個li</li>
<li id="li3">我是第3個li</li>
</ul>
我們的需求是,點選不同列,輸出不同的訊息。
- 第一種做法:給每個
<li>
新增點選事件,這樣能分別處理事件,展示不同的內容。
document.getElementById('li1').addEventListener('click', function(e) {
console.log('我是第一個li')
}, false)
document.getElementById('li2').addEventListener('click', function(e) {
console.log('我是第2個li')
}, false)
document.getElementById('li3').addEventListener('click', function(e) {
console.log('我是第3個li')
}, false)
單擊每一個<li>
,會輸出對應的內容。
- 第二種做法:給
<li>
元素的父元素<ul>
新增一個處理事件,
document.querySelector('ul').addEventListener('click', function (e) {
console.log(e.target.innerText)
}, false)
單擊每一個<li>
,會展示不同的<li>
中文字元素內容。
在這段程式碼中,我們只為<ul>
元素添加了一個onclick事件處理程式。由於所有<li>
都是<ul>
元素的子節點,而且它們的事件會冒泡,所以單擊事件最終會被這個函式處理。
以上兩種方式,第二種所具有的優勢:
事前消耗更低。因為只取得了一個DOM元素,只添加了一個事件處理程式。
佔用的記憶體更少。每個函式都是物件,都會佔用記憶體。
效能更優。 記憶體中的物件越多,效能就越差。
如果以後要增減
<li>
元素,也不用修改事件方法,可以獲取相同的處理結果。
所以,比較推薦使用第二種方式。
最適合採用事件委託技術的事件包括click
、mousedown
、mouseup
、keydown
、keyup
和keypress
。雖然mouseover
和mouseout
事件也冒泡,但要適當處理它們並不容易,而且經常要計算元素的位置。
參考資料:
JavaScript高階程式設計(第三版)- 第13章 事件
相關推薦
js事件流機制冒泡和捕獲
JavaScript與HTML之間的互動是通過事件實現的。事件,就是文件或瀏覽器視窗中發生的一些特定的互動瞬間。 事件流 從頁面中接收事件的順序稱為事件流。 IE --> 事件冒泡流 Netscape --> 事件捕獲流 事件冒泡 IE的事件流叫做事件冒泡(event bubbling),即事件
JS事件流(事件冒泡和事件捕獲)
事件流是描述從頁面接收事件的順序。但是有意思的是,IE和Netscape開發團隊提出了差不多完全相反的事件流概念。IE的事件流是事件冒泡流,而Netspace Communicator的事件流是事件捕獲流。 事件冒泡 IE的事件流叫做事件冒泡(event
js 事件流的事件冒泡和事件捕獲與阻止事件傳播
head 阻止事件冒泡 觸發 事件冒泡 單擊 期望 就會 簡單的 出現異常 為了方便引入事件流的概念,我們先來說說什麽是事件。 事件就是用戶或瀏覽器自身執行的某種動作。換句話說,我們在瀏覽網頁或者 APP 時,通常會在設備上產生很多交互性的操作,例如點擊、選擇、滾動屏幕、鍵
js事件流 事件捕獲 及時間冒泡詳解
Javascript與HTML之間的互動是通過事件實現。 一、事件流 事件,是文件或瀏覽器視窗中發生的一些特定的互動瞬間。事件流,描述的是頁面中接受事件的順序。IE9,chrome,Firefox,Opera,Safari均實現了DOM2級規範中定義的標準DOM事件,而IE8和IE8以下版本仍然保留專有的
11.JS-事件流-冒泡、捕獲
事件流: 頁面接受事件的順序 DOM事件流: 當事件發生時,事件會在該元素節點和根節點之間的路徑進行傳播,傳播過程中所遇到的節點都會接受該事件 冒泡:從最具體元素傳播最不具體的元素
事件流(事件冒泡和捕獲,函式閉包等)
事件流 事件流描述的是從頁面中接受事件的順序,當幾個都具有事件的元素層疊在一起的時候,那麼你點選其中一個元素,並不是只有當前被點選的元素會觸發事件,而層疊在你點選範圍的所有元素都會觸發事件。 事件流包括兩種模式:冒泡和捕獲 事件捕獲: 父級元素先觸發,子集元素後觸發;(由外到
js 事件流,事件冒泡機制
事件冒泡:當一個元素接收到事件的時候,會把他接收到的所有傳播給他的父級,一直到頂層window, <!DOCTYPE html> <html> <head> &nb
js基礎之冒泡和捕獲機制
DOM事件所囊括的知識較為龐雜,本片文章總結一下冒泡和捕獲機制到底是怎麼運作的。 事件流 當我們點選頁面上的一個按鈕的時候,是按鈕最外層的父元素先收到事件並執行,還是這個被我們點選的按鈕先收到事件並執行?所以這兒引入了事件流的概念:事件流所描述的就是
js事件流之事件冒泡的應用----事件委託
什麼是事件委託? 它還有一個名字叫事件代理。 JavaScript高階程式設計上講: 事件委託就是利用事件冒泡,只指定一個事件處理程式,就可以管理某一型別的所有事件。 用取快遞來解釋這個現象,大家認真領會一下事件委託到底是一個什麼原理: 有三個同事預計會在週一收到快遞。為簽收快遞,有兩種辦法:一
js事件流之事件冒泡的應用----事件委托
mouseout 目標 呵呵 內存占用 設計 onload end elements bre 什麽是事件委托? 它還有一個名字叫事件代理。 JavaScript高級程序設計上講: 事件委托就是利用事件冒泡,只指定一個事件處理程序,就可以管理某一類型的所有事件。 用取快遞來解
JS事件流和事件委託
在上一篇《JS知識點大雜燴》中說到了事件流但沒有詳細的介紹,這篇文章就來介紹一下事件流。 事件流一共由三個階段分別是: 1.捕獲階段 2.目標階段 3.冒泡階段 複製程式碼 事件繫結大家都知道,有DOM0級(on+type)和DOM2級(addEventListener),我覺得說那麼多概念不好理解,直
JS事件之事件流機制
眾所周知JS和HTMl元素的互動幾乎都是通過“事件”來完成的,事件從觸發到完成響應一般分為3個階段:捕獲階段,目標階段,和冒泡階段。 那麼事件是在捕獲階段響應 還是在冒泡階段響應那?? 我們是可以手動
事件冒泡和捕獲 觸發
什麼是事件? 事件是文件和瀏覽器視窗中發生的特定的互動瞬間。 事件是javascript應用跳動的心臟,也是把所有東西黏在一起的膠水,當我們與瀏覽器中web頁面進行某些型別的互動時,事件就發生了。 事件可能是使用者在某些內容上的點選,滑鼠經過某個特定元素或按下鍵盤
js事件流
事件冒泡 指定 cancel util detach name prevent sdn details 1.HTML事件處理程序: JS事件放在HTML裏面。 <!DOCTYPE html> <html> <head
一次關於js事件出發機制反常的解決記錄
add 行為 click事件 解除綁定 部分 win 窗口 www child 起因:正常情況下我點擊s2時是先彈出我是children,再彈出我是father,但是卻出現了先彈出我是father,後彈出我是children的情況,這種情況是在和安卓app交互的h5頁面中出
js 事件流
表示 return nbsp 頻繁 三個參數 阻止 實現 事件捕獲 需要 什麽是事件? 事件是文檔或瀏覽器窗口發生的一些特定的交互瞬間, 比如 點擊 雙擊 滾動條滑動…… 什麽是事件流? 事件流指的是 從頁面接收事件的順序。 關於事件流,IE和Netscape提出了差不多相
關於JS事件迴圈機制
早些時候因為看到一個JS面試題,在這篇文章(例項理解promise、macro-task、micro-task)中有談到過一些事件迴圈機制的問題,但是因為找了多方資料整理出來的,某些概念說的還是不清楚 看到下面這篇文章,對事件迴圈機制介紹的思路很清晰,值得存檔學習 https://mp.we
setTimeOut引發的思考——初步理解JS事件迴圈機制 Event Loop
JS是單執行緒引擎,線上程中擁有唯一一個事件迴圈(web workder涉及到了多執行緒,再做補充) JS程式碼執行過程中,除了依靠函式呼叫棧順序執行JS程式碼,還依靠任務佇列(task queue)執行一些程式碼。 一個執行緒中,事件迴圈是唯一的,但是任務佇列
JS事件迴圈機制(event loop)
一 前言 相信所有學過 JavaScript 都知道它是一門單執行緒的語言,這也就意味著 JS 無法進行多執行緒程式設計,但是 JS 當中卻有著無處不在的非同步概念 。在初期許多人會把非同步理解成類似多執行緒的程式設計模式,其實他們中有著很大的差別,要完全理解非
addEventListener 冒泡 和 捕獲
#div1 { width: 500px; height: 300px; background-color: #4fc08d; display:flex; justify-content:center; align-items:center; } #