最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

JavaScript?事件流:從"捕獲"到"冒泡"的完整旅程

 更新時(shí)間:2026年05月07日 10:35:44   作者:yqcoder  
這篇文章給大家介紹JavaScript事件流:從“捕獲”到“冒泡”的完整旅程,本文結(jié)合實(shí)例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧

當(dāng)你點(diǎn)擊頁面上的一個(gè)按鈕時(shí),這個(gè)點(diǎn)擊動(dòng)作并不是瞬間只在按鈕上發(fā)生的。
在瀏覽器的世界里,這個(gè)點(diǎn)擊事件像一陣風(fēng),經(jīng)歷了一場從上到下,再從下到上的完整旅行。

這就是 DOM 事件流(Event Flow)。

1. ?? 什么是事件流?

定義
事件流描述的是從頁面中接收事件的順序。

在早期的瀏覽器大戰(zhàn)中, Netscape(網(wǎng)景)和 IE 提出了兩種完全相反的事件傳播模型:

  • Netscape:主張事件捕獲(Event Capturing),即事件從最外層向內(nèi)層傳播。
  • IE:主張事件冒泡(Event Bubbling),即事件從最內(nèi)層向外層傳播。

最終,W3C 制定了標(biāo)準(zhǔn),將兩者結(jié)合:先捕獲,后冒泡

通俗比喻
想象你在一個(gè)多層辦公樓里扔了一個(gè)石子(觸發(fā)事件)。

  1. 捕獲階段:石子從樓頂(window)一層層往下掉,經(jīng)過每一層的地板。
  2. 目標(biāo)階段:石子落在了某一層的具體房間(目標(biāo)元素)里。
  3. 冒泡階段:石子落地后產(chǎn)生的回聲或震動(dòng),從那個(gè)房間一層層往上傳播回樓頂。

2. ?? 事件流的三個(gè)階段

當(dāng)一個(gè)事件發(fā)生時(shí),它會(huì)依次經(jīng)歷以下三個(gè)階段:

第一階段:捕獲階段(Capturing Phase)

  • 方向:從根節(jié)點(diǎn)(window / document)向下傳播,直到目標(biāo)元素的父元素。
  • 特點(diǎn):此時(shí)事件正在“尋找”目標(biāo)。
  • 注意:默認(rèn)情況下,我們注冊的事件監(jiān)聽器不會(huì)在這個(gè)階段觸發(fā)(除非特別指定)。

第二階段:目標(biāo)階段(Target Phase)

  • 方向:事件到達(dá)實(shí)際觸發(fā)事件的元素(event.target)。
  • 特點(diǎn):這是事件真正發(fā)生的地方。

第三階段:冒泡階段(Bubbling Phase)

  • 方向:從目標(biāo)元素向上傳播,經(jīng)過父元素、祖父元素……直到根節(jié)點(diǎn)。
  • 特點(diǎn):這是最常用的階段。大多數(shù)事件監(jiān)聽器默認(rèn)都注冊在這個(gè)階段。
      Window
        |
      Document
        |
       HTML
        |
       Body          <--- 1. 捕獲階段 (向下)
        |            <--- 2. 目標(biāo)階段 (到達(dá) div#target)
      Div#container  <--- 3. 冒泡階段 (向上)
        |
      Div#target     (你點(diǎn)擊了這里)

3. ?? 代碼實(shí)戰(zhàn):如何控制捕獲與冒泡?

在 JavaScript 中,我們使用 addEventListener 來注冊事件。它的第三個(gè)參數(shù)決定了監(jiān)聽器在哪個(gè)階段觸發(fā)。

語法

element.addEventListener(event, handler, useCapture);
  • useCapturetrue:在捕獲階段觸發(fā)。
  • useCapturefalse(默認(rèn)):在冒泡階段觸發(fā)。

?? 實(shí)驗(yàn)代碼

假設(shè)我們有如下 HTML 結(jié)構(gòu):

<div id="grandparent">
  爺爺
  <div id="parent">
    爸爸
    <div id="child">兒子</div>
  </div>
</div>

我們給每一層都綁定點(diǎn)擊事件,分別測試捕獲和冒泡:

const grandparent = document.getElementById("grandparent");
const parent = document.getElementById("parent");
const child = document.getElementById("child");
function log(msg, phase) {
  console.log(`${msg} - ${phase}`);
}
// 1. 注冊捕獲階段監(jiān)聽器 (useCapture = true)
grandparent.addEventListener(
  "click",
  () => log("Grandparent", "Capture"),
  true,
);
parent.addEventListener("click", () => log("Parent", "Capture"), true);
// 2. 注冊冒泡階段監(jiān)聽器 (useCapture = false, 默認(rèn))
parent.addEventListener("click", () => log("Parent", "Bubble"));
child.addEventListener("click", () => log("Child", "Bubble"));
// 3. 點(diǎn)擊 "兒子" (child)

?? 輸出結(jié)果

當(dāng)你點(diǎn)擊 <div id="child"> 時(shí),控制臺(tái)輸出順序如下:

  1. Grandparent - Capture (捕獲:從外向內(nèi))
  2. Parent - Capture (捕獲:從外向內(nèi))
  3. Child - Bubble (目標(biāo):通常視為冒泡的一部分,或者單獨(dú)的目標(biāo)階段)
  4. Parent - Bubble (冒泡:從內(nèi)向外)

注意grandparent 沒有注冊冒泡監(jiān)聽器,所以最后沒有輸出 Grandparent - Bubble。

4. ?? 如何阻止事件傳播?

有時(shí)候,我們不希望事件繼續(xù)傳播(例如:點(diǎn)擊彈窗內(nèi)部不希望關(guān)閉彈窗,但點(diǎn)擊背景要關(guān)閉)。

方法一:event.stopPropagation()

作用:停止事件在 DOM 樹中的進(jìn)一步傳播(既阻止后續(xù)的捕獲,也阻止后續(xù)的冒泡)。

child.addEventListener("click", function (event) {
  event.stopPropagation();
  console.log("Child clicked, stop!");
});

結(jié)果:點(diǎn)擊 child 后,只會(huì)執(zhí)行 child 的回調(diào),parentgrandparent 的回調(diào)都不會(huì)執(zhí)行。

方法二:event.stopImmediatePropagation()

作用:不僅阻止事件傳播,還阻止當(dāng)前元素上其他相同事件的監(jiān)聽器執(zhí)行。

child.addEventListener("click", function (event) {
  event.stopImmediatePropagation();
  console.log("Handler 1");
});
child.addEventListener("click", function () {
  console.log("Handler 2"); // 這行永遠(yuǎn)不會(huì)執(zhí)行
});

? 誤區(qū):return false

在 jQuery 中,return false 等價(jià)于同時(shí)調(diào)用 stopPropagation()preventDefault()
但在原生 JS 中,return false 無效,必須顯式調(diào)用上述方法。

5. ?? 實(shí)際應(yīng)用場景:為什么我們需要它們?

場景一:事件委托(利用冒泡)

這是冒泡最著名的應(yīng)用。與其給 1000 個(gè)列表項(xiàng)分別綁定事件,不如給父元素 <ul> 綁定一個(gè)事件,利用冒泡機(jī)制統(tǒng)一處理。

// 利用冒泡,只在 ul 上監(jiān)聽
ul.addEventListener("click", function (event) {
  if (event.target.tagName === "LI") {
    console.log("Clicked:", event.target.innerText);
  }
});

場景二:模態(tài)框關(guān)閉邏輯(混合使用)

常見需求:點(diǎn)擊遮罩層關(guān)閉彈窗,點(diǎn)擊彈窗內(nèi)容不關(guān)閉。

<div id="overlay">
  <div id="modal">內(nèi)容...</div>
</div>
const overlay = document.getElementById("overlay");
const modal = document.getElementById("modal");
// 1. 點(diǎn)擊遮罩層,關(guān)閉彈窗(冒泡階段)
overlay.addEventListener("click", () => {
  console.log("Close Modal");
});
// 2. 點(diǎn)擊彈窗內(nèi)部,阻止冒泡,防止觸發(fā) overlay 的點(diǎn)擊事件
modal.addEventListener("click", (event) => {
  event.stopPropagation();
  console.log("Modal Content Clicked");
});

場景三:高級攔截(利用捕獲)

如果你想在一個(gè)事件到達(dá)目標(biāo)之前“攔截”它(例如全局權(quán)限檢查、日志記錄),可以使用捕獲階段。因?yàn)椴东@發(fā)生在冒泡之前,你可以提前終止事件。

// 在捕獲階段攔截所有點(diǎn)擊
document.addEventListener(
  "click",
  (event) => {
    if (event.target.disabled) {
      event.stopPropagation(); // 禁止點(diǎn)擊禁用元素
      event.preventDefault();
    }
  },
  true,
); // 注意這里是 true

?? 總結(jié)

特性事件捕獲 (Capturing)事件冒泡 (Bubbling)
傳播方向從上到下 (Window -> Target)從下到上 (Target -> Window)
觸發(fā)時(shí)機(jī)早期,用于攔截晚期,用于處理
默認(rèn)行為需設(shè)置 useCapture: true默認(rèn) (useCapture: false)
主要用途事件攔截、全局監(jiān)聽事件委托、常規(guī)交互

?? 博主寄語
事件流就像水的流動(dòng),既有從天而降的雨(捕獲),也有匯聚成河向上的蒸汽(冒泡)。

記住三個(gè)關(guān)鍵點(diǎn)

  1. 順序:先捕獲,后目標(biāo),再冒泡。
  2. 委托:利用冒泡實(shí)現(xiàn)高性能的事件代理。
  3. 阻止:使用 stopPropagation() 控制事件傳播范圍。

理解了事件流,你就掌握了 DOM 交互的脈搏!

希望這篇文檔能幫你徹底搞懂事件捕獲與冒泡!

到此這篇關(guān)于JavaScript 事件流:從“捕獲”到“冒泡”的完整旅程的文章就介紹到這了,更多相關(guān)js事件流從捕獲到冒泡內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • javascript簡單進(jìn)制轉(zhuǎn)換實(shí)現(xiàn)方法

    javascript簡單進(jìn)制轉(zhuǎn)換實(shí)現(xiàn)方法

    這篇文章主要介紹了javascript簡單進(jìn)制轉(zhuǎn)換實(shí)現(xiàn)方法,涉及javascript字符串轉(zhuǎn)換與數(shù)值操作相關(guān)技巧,需要的朋友可以參考下
    2016-11-11
  • JavaScript對象參數(shù)的引用傳遞

    JavaScript對象參數(shù)的引用傳遞

    這篇文章主要為大家介紹了JavaScript對象參數(shù)的引用傳遞的相關(guān)資料,感興趣的小伙伴們可以參考一下
    2016-01-01
  • 微信小程序開發(fā)自定義tabBar實(shí)戰(zhàn)案例(定制消息99+小紅心)

    微信小程序開發(fā)自定義tabBar實(shí)戰(zhàn)案例(定制消息99+小紅心)

    一定的需求情況下無法使用小程序原生的tabbar的時(shí)候,需要自行實(shí)現(xiàn)一個(gè)和tabbar功能一模一樣的自制組件,下面這篇文章主要給大家介紹了關(guān)于微信小程序開發(fā)自定義tabBar(定制消息99+小紅心)的相關(guān)資料,需要的朋友可以參考下
    2022-12-12
  • BootStrap的JS插件之輪播效果案例詳解

    BootStrap的JS插件之輪播效果案例詳解

    Bootstrap 是一個(gè)用于快速開發(fā) Web 應(yīng)用程序和網(wǎng)站的前端框架。這篇文章主要介紹了BootStrap的JS插件之輪播效果案例詳解的相關(guān)資料,需要的朋友可以參考下
    2016-05-05
  • 在uni-app中自定義輸入框placeholder的樣式的問題示例展示

    在uni-app中自定義輸入框placeholder的樣式的問題示例展示

    這篇文章主要介紹了在uni-app中自定義輸入框placeholder的樣式的問題示例展示,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),感興趣的朋友一起看看吧
    2025-05-05
  • 前端監(jiān)控頁面異常的常用方法

    前端監(jiān)控頁面異常的常用方法

    前端開發(fā)常見問題之一: 資源異常、js異常,頁面出了問題常見的想法是:如何看到錯(cuò)誤信息,資源腳本是否正常,像js、css、圖片這些資源文件經(jīng)常受網(wǎng)絡(luò)等原因,導(dǎo)致資源加載異常,這些會(huì)直接影響我們的頁面,本文給大家介紹前端監(jiān)控頁面異常的常用方法,需要的朋友可以參考下
    2025-04-04
  • 微信小程序?qū)崿F(xiàn)點(diǎn)擊按鈕修改文字大小功能【附demo源碼下載】

    微信小程序?qū)崿F(xiàn)點(diǎn)擊按鈕修改文字大小功能【附demo源碼下載】

    這篇文章主要介紹了微信小程序?qū)崿F(xiàn)點(diǎn)擊按鈕修改文字大小功能,涉及微信小程序事件綁定及setData動(dòng)態(tài)修改Page頁面data數(shù)據(jù),進(jìn)而控制頁面元素屬性動(dòng)態(tài)改變的相關(guān)操作技巧,需要的朋友可以參考下
    2017-12-12
  • JS解決url傳值出現(xiàn)中文亂碼的另類辦法

    JS解決url傳值出現(xiàn)中文亂碼的另類辦法

    為什么用表單的方式就可以傳遞中文,而URL的方式就不行了呢?非得用URL傳值的方式才能解決問題嗎?這里我想到了動(dòng)態(tài)表單,何不用它來解決呢
    2013-04-04
  • es6 for循環(huán)中l(wèi)et和var區(qū)別詳解

    es6 for循環(huán)中l(wèi)et和var區(qū)別詳解

    這篇文章主要介紹了es6 for循環(huán)中l(wèi)et和var區(qū)別詳解,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-01-01
  • JAVASCRIPT style 中visibility和display之間的區(qū)別

    JAVASCRIPT style 中visibility和display之間的區(qū)別

    visibility屬性用來確定元素是顯示還是隱藏的,這用visibility="visible|hidden"來表示(visible表示顯示,hidden表示隱藏)。
    2010-01-01

最新評論

平阳县| 墨脱县| 高要市| 海伦市| 英德市| 镇远县| 高淳县| 永仁县| 皋兰县| 延长县| 屯留县| 南开区| 玉门市| 彭州市| 古浪县| 罗定市| 鄱阳县| 恩平市| 资中县| 萍乡市| 阜南县| 寿宁县| 临夏市| 仁化县| 荣成市| 玉环县| 敖汉旗| 德令哈市| 赣州市| 阜新市| 外汇| 榆社县| 彭阳县| 肇州县| 梁平县| 新丰县| 元朗区| 龙游县| 理塘县| 宁河县| 大余县|