1. 程式人生 > >js事件流機制冒泡和捕獲

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級事件”規定的事件流包括三個階段:事件捕獲階段、處於目標階段和事件冒泡階段。

首先發生的是事件捕獲,為截獲事件提供了機會。然後是實際的目標接收到事件。最後一個階段是冒泡階段,可以在這個階段對事件作出響應。

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>元素的子節點,而且它們的事件會冒泡,所以單擊事件最終會被這個函式處理。

以上兩種方式,第二種所具有的優勢:

  1. 事前消耗更低。因為只取得了一個DOM元素,只添加了一個事件處理程式。

  2. 佔用的記憶體更少。每個函式都是物件,都會佔用記憶體。

  3. 效能更優。 記憶體中的物件越多,效能就越差。

  4. 如果以後要增減<li>元素,也不用修改事件方法,可以獲取相同的處理結果。

所以,比較推薦使用第二種方式。

最適合採用事件委託技術的事件包括clickmousedownmouseupkeydownkeyupkeypress。雖然mouseovermouseout事件也冒泡,但要適當處理它們並不容易,而且經常要計算元素的位置。

參考資料:

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; } #