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

JavaScript事件機(jī)制之捕獲、冒泡與事件委托詳解

 更新時(shí)間:2025年11月26日 10:47:03   作者:秋氘漁  
JavaScript事件機(jī)制是指在JavaScript中處理用戶交互或其他事件的機(jī)制,這篇文章主要介紹了JavaScript事件機(jī)制之捕獲、冒泡與事件委托的相關(guān)資料,文中通過代碼介紹的非常詳細(xì),需要的朋友可以參考下

1.什么是JavaScript的事件機(jī)制?

JavaScript的事件機(jī)制一共分為三個(gè)部分,分別是事件捕獲,事件冒泡事件委托。

(1)事件捕獲:指的是事件從根節(jié)點(diǎn)(document節(jié)點(diǎn))向目標(biāo)事件傳播的過程。

(2)事件冒泡:指的是當(dāng)捕獲到目標(biāo)事件之后從目標(biāo)事件開始向上傳播(傳播至Document節(jié)點(diǎn))的過程。

(3)事件委托:指的是利用事件冒泡機(jī)制,在對應(yīng)子元素的父元素節(jié)點(diǎn)上綁定事件處理器,避免對多個(gè)子元素分別綁定事件監(jiān)聽器。這樣做可以顯著減少內(nèi)存占用和事件處理器的數(shù)量,提升頁面性能,尤其是在子元素?cái)?shù)量很多或動態(tài)生成的場景下,事件委托能降低瀏覽器的事件管理開銷,提高響應(yīng)效率和代碼維護(hù)性。

想要掌握好JavaScript中的事件機(jī)制,首先掌握好事件是如何被捕獲的(事件捕獲階段),捕獲到了事件是怎么觸發(fā)的(事件執(zhí)行階段),事件觸發(fā)之后會怎么樣(事件冒泡階段)。理解這些之后就知道如何利用事件冒泡來進(jìn)行事件委托了。

2.DOM樹

在講述事件機(jī)制之前,首先掌握一個(gè)概念,什么是DOM樹。理解了DOM樹可以讓我們更好的理解事件的觸發(fā)和冒泡過程。

什么是DOM樹?

  • DOM(文檔對象模型,Document Object Model)是瀏覽器解析HTML后生成的一個(gè)樹狀結(jié)構(gòu)。
  • 每個(gè)HTML標(biāo)簽、文本節(jié)點(diǎn)、屬性都會被表示成DOM樹上的一個(gè)節(jié)點(diǎn)。
  • 通過DOM樹,JavaScript可以訪問、修改網(wǎng)頁內(nèi)容和結(jié)構(gòu)。

案例:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <div id="container">
      <button id="btn">點(diǎn)擊我</button>
    </div>

</body>
</html>

DOM樹為:

Document
 └── html
      └── body
           └── div#container
                └── button#btn (文本節(jié)點(diǎn): "點(diǎn)擊我")

3.事件觸發(fā)流程

假設(shè)我們在上面HTML中給按鈕和它的父元素div都綁定點(diǎn)擊事件:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <div id="container">
      <button id="btn">點(diǎn)擊我</button>
    </div>

    <script>
      const container = document.getElementById('container');
      const btn = document.getElementById('btn');

      container.addEventListener('click', () => {
        console.log('容器被點(diǎn)擊');
      });

      btn.addEventListener('click', () => {
        console.log('按鈕被點(diǎn)擊');
      });
    </script>


</body>
</html>

事件觸發(fā)流程:

  1. 當(dāng)用戶點(diǎn)擊按鈕時(shí),瀏覽器根據(jù)DOM樹找到事件目標(biāo)(button)。
  2. 事件先從document開始捕獲,經(jīng)過html、body、div,最后到button(捕獲階段)。明事件捕獲默認(rèn)是不啟用的,需要在addEventListener第三個(gè)參數(shù)設(shè)置為true才會執(zhí)行捕獲階段的監(jiān)聽。否則事件監(jiān)聽默認(rèn)只在目標(biāo)階段和冒泡階段觸發(fā)。
  3. 事件在button上觸發(fā)(目標(biāo)階段)。
  4. 事件從button向上冒泡,經(jīng)過div、body、html、document(冒泡階段)。
  5. 綁定在button和container上的事件都會被觸發(fā),輸出:按鈕被點(diǎn)擊 容器被點(diǎn)擊。

從上述案例我們可以看出,當(dāng)我們在給一個(gè)事件綁定了監(jiān)聽器之后,如果該監(jiān)聽器被觸發(fā)了,瀏覽器首先需要找到目標(biāo)元素(捕獲階段),找到目標(biāo)元素之后瀏覽器會觸發(fā)當(dāng)前元素綁定的事件監(jiān)聽器的事件(目標(biāo)階段),當(dāng)執(zhí)行完當(dāng)前的事件之后會繼續(xù)沿著DOM樹向上觸發(fā)(冒泡階段),由于<div id="container">是該按鈕的父元素并且也綁定了事件監(jiān)聽,所以也會觸發(fā),直至傳遞到根節(jié)點(diǎn)。

4. 如何利用事件冒泡機(jī)制(事件委托)

假設(shè)你有一個(gè)列表,里面有很多條目,每條目都有一個(gè)“刪除”按鈕:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <ul id="list">
      <li>項(xiàng)目1 <button class="delete-btn">刪除</button></li>
      <li>項(xiàng)目2 <button class="delete-btn">刪除</button></li>
      <li>項(xiàng)目3 <button class="delete-btn">刪除</button></li>
      <!-- 可能還有更多項(xiàng)目 -->
    </ul>


</body>
</html>

(1)傳統(tǒng)做法(不使用事件委托):

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <ul id="list">
      <li>項(xiàng)目1 <button class="delete-btn">刪除</button></li>
      <li>項(xiàng)目2 <button class="delete-btn">刪除</button></li>
      <li>項(xiàng)目3 <button class="delete-btn">刪除</button></li>
      <!-- 可能還有更多項(xiàng)目 -->
    </ul>
    <script>
        const deleteButtons = document.querySelectorAll('.delete-btn');
        deleteButtons.forEach(btn => {
          btn.addEventListener('click', function() {
            const li = this.parentElement;
            li.remove();
            console.log('刪除了一個(gè)項(xiàng)目');
          });
        });

    </script>


</body>
</html>

我們發(fā)現(xiàn),如果想要點(diǎn)擊按鈕就刪除對應(yīng)元素,我們可以給每一個(gè)按鈕都綁定事件監(jiān)聽器來達(dá)到效果。這樣對于少部分的事件其實(shí)并沒有什么影響,但是如果事件很多的情況下,綁定大量事件監(jiān)聽器會消耗內(nèi)存和性能。而且如果后來還需要動態(tài)添加新的項(xiàng)目,則需要額外綁定事件。

(2)利用事件冒泡機(jī)制(事件委托)

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <ul id="list">
      <li>項(xiàng)目1 <button class="delete-btn">刪除</button></li>
      <li>項(xiàng)目2 <button class="delete-btn">刪除</button></li>
      <li>項(xiàng)目3 <button class="delete-btn">刪除</button></li>
      <!-- 可能還有更多項(xiàng)目 -->
    </ul>
    <script>
        const list = document.getElementById('list');

        list.addEventListener('click', function(event) {
          // 利用事件冒泡,判斷點(diǎn)擊目標(biāo)是否是刪除按鈕
          if (event.target && event.target.classList.contains('delete-btn')) {
            const li = event.target.parentElement;
            li.remove();
            console.log('刪除了一個(gè)項(xiàng)目(事件委托)');
          }
        });

    </script>


</body>
</html>

從上述案例我們可以發(fā)現(xiàn),我們只綁定了一個(gè)事件監(jiān)聽(ul),但是當(dāng)子元素(li)觸發(fā)點(diǎn)擊事件之后,我們并沒有對子元素綁定事件處理,但是也能夠進(jìn)行刪除操作,這是因?yàn)樽釉氐氖录刂鳧OM樹向上傳播,當(dāng)傳播到ul節(jié)點(diǎn)的時(shí)候觸發(fā)了ul的事件處理機(jī)制。所以進(jìn)行了刪除。

5.如何阻止事件冒泡

當(dāng)我們希望事件只在某個(gè)特定元素上響應(yīng),而不影響其父元素或祖先元素時(shí),可以使用 event.stopPropagation() 來阻止事件冒泡。

此外,如果希望不僅阻止事件冒泡,還阻止當(dāng)前元素上后續(xù)的同類型事件監(jiān)聽器執(zhí)行,可以使用 event.stopImmediatePropagation()

區(qū)別:

  • event.stopPropagation():阻止事件繼續(xù)冒泡到父元素,但當(dāng)前元素上綁定的其他同類型事件監(jiān)聽器仍會執(zhí)行。
  • event.stopImmediatePropagation():阻止事件冒泡,并且阻止當(dāng)前元素上后續(xù)同類型事件監(jiān)聽器的執(zhí)行。

案例:

<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8" />
  <title>阻止事件冒泡案例</title>
</head>
<body>
  <div id="outer" style="padding:20px; border:1px solid #ccc;">
    外層容器(點(diǎn)擊會觸發(fā))
    <button id="inner">點(diǎn)擊我</button>
  </div>

  <script>
    const outer = document.getElementById('outer');
    const inner = document.getElementById('inner');

    outer.addEventListener('click', () => {
      console.log('【外層容器】點(diǎn)擊事件觸發(fā)');
    });

    // 監(jiān)聽器1:使用 stopPropagation()
    inner.addEventListener('click', (event) => {
      event.stopPropagation();  // 阻止事件冒泡,父元素的點(diǎn)擊事件不會觸發(fā)
      console.log('【按鈕監(jiān)聽器1】點(diǎn)擊事件觸發(fā),事件冒泡被阻止,父元素不會收到事件');
    });

    // 監(jiān)聽器2:同一元素上的另一個(gè)監(jiān)聽器
    inner.addEventListener('click', () => {
      console.log('【按鈕監(jiān)聽器2】點(diǎn)擊事件觸發(fā),仍然執(zhí)行');
    });

    /*
    // 如果改為使用 stopImmediatePropagation(),效果如下:
    inner.addEventListener('click', (event) => {
      event.stopImmediatePropagation();  // 阻止事件冒泡,且阻止后續(xù)監(jiān)聽器執(zhí)行
      console.log('【按鈕監(jiān)聽器1】點(diǎn)擊事件觸發(fā),事件冒泡和后續(xù)監(jiān)聽器執(zhí)行被阻止,父元素不會收到事件');
    });

    inner.addEventListener('click', () => {
      console.log('【按鈕監(jiān)聽器2】不會執(zhí)行');
    });
    */
  </script>
</body>
</html>

使用 stopPropagation() 時(shí):

點(diǎn)擊按鈕會輸出:

【按鈕監(jiān)聽器1】點(diǎn)擊事件觸發(fā),事件冒泡被阻止,父元素不會收到事件
【按鈕監(jiān)聽器2】點(diǎn)擊事件觸發(fā),仍然執(zhí)行

使用 stopImmediatePropagation() 時(shí):

點(diǎn)擊按鈕只會輸出:

【按鈕監(jiān)聽器1】點(diǎn)擊事件觸發(fā),事件冒泡和后續(xù)監(jiān)聽器執(zhí)行被阻止,父元素不會收到事件

6.總結(jié)

  • JavaScript事件機(jī)制包括三個(gè)主要階段:

    1. 捕獲階段:事件從document節(jié)點(diǎn)向目標(biāo)元素逐層傳遞,監(jiān)聽器在此階段觸發(fā)需設(shè)置capturetrue。
    2. 目標(biāo)階段:事件到達(dá)目標(biāo)元素,觸發(fā)綁定在目標(biāo)元素上的事件監(jiān)聽器。
    3. 冒泡階段:事件從目標(biāo)元素向上傳播到document,觸發(fā)沿途元素綁定的冒泡監(jiān)聽器。
  • 事件冒泡機(jī)制允許我們通過事件委托,只在父元素上綁定事件監(jiān)聽器,利用事件冒泡捕獲子元素事件,極大優(yōu)化性能和代碼維護(hù)。

  • 在需要阻止事件傳播時(shí),可使用event.stopPropagation()阻止冒泡,避免父元素響應(yīng)事件;使用event.stopImmediatePropagation()則進(jìn)一步阻止當(dāng)前元素上后續(xù)同類型監(jiān)聽器執(zhí)行。

  • 事件監(jiān)聽器默認(rèn)在目標(biāo)階段和冒泡階段觸發(fā),捕獲階段監(jiān)聽需要顯式開啟

到此這篇關(guān)于JavaScript事件機(jī)制之捕獲、冒泡與事件委托的文章就介紹到這了,更多相關(guān)JS事件捕獲、冒泡與事件委托內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 手機(jī)軟鍵盤彈出時(shí)影響布局的解決方法

    手機(jī)軟鍵盤彈出時(shí)影響布局的解決方法

    這篇文章主要介紹了手機(jī)軟鍵盤彈出時(shí)影響布局的解決方法的相關(guān)資料,大家開發(fā)移動端的軟件時(shí)候,肯定會因?yàn)檐涙I盤的彈窗影響布局,這里說下如何解決,需要的朋友可以參考下
    2016-12-12
  • JavaScript中獲取選擇器的方式舉例詳解

    JavaScript中獲取選擇器的方式舉例詳解

    在JavaScript中選擇器是一種強(qiáng)大的工具,用于從HTML文檔中選擇和操作元素,通過選擇器,可以輕松地找到特定的元素,并對其進(jìn)行各種操作,這篇文章主要介紹了JavaScript中獲取選擇器的相關(guān)資料,需要的朋友可以參考下
    2025-08-08
  • 通過Javascript創(chuàng)建一個(gè)選擇文件的對話框代碼

    通過Javascript創(chuàng)建一個(gè)選擇文件的對話框代碼

    通過Javascript創(chuàng)建一個(gè)選擇文件的對話框代碼,需要的朋友可以參考下
    2012-06-06
  • 利用JavaScript的%做隔行換色的實(shí)例

    利用JavaScript的%做隔行換色的實(shí)例

    下面小編就為大家分享一篇利用JavaScript的%做隔行換色的實(shí)例,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2017-11-11
  • Javascript改變CSS樣式(局部和全局)

    Javascript改變CSS樣式(局部和全局)

    改變CSS樣式分為局部和全局,下面為大家介紹下使用Javascript具體的實(shí)現(xiàn),感興趣的朋友可以參考下
    2013-12-12
  • 理解Javascript_07_理解instanceof實(shí)現(xiàn)原理

    理解Javascript_07_理解instanceof實(shí)現(xiàn)原理

    在《Javascript類型檢測》一文中講到了用instanceof來用做檢測類型,讓我們來回顧一下
    2010-10-10
  • JS實(shí)現(xiàn)數(shù)組按升序及降序排列的方法

    JS實(shí)現(xiàn)數(shù)組按升序及降序排列的方法

    這篇文章主要介紹了JS實(shí)現(xiàn)數(shù)組按升序及降序排列的方法,涉及javascript針對數(shù)組的簡單排序操作相關(guān)實(shí)現(xiàn)技巧,需要的朋友可以參考下
    2017-04-04
  • 簡單了解TypeScript中如何繼承 Error 類

    簡單了解TypeScript中如何繼承 Error 類

    這篇文章主要介紹了簡單了解TypeScript中如何繼承 Error 類,一個(gè)典型的網(wǎng)站服務(wù)器可能需要有 NetworkError, DatabaseError, UnauthorizedError 等。 我們希望這些類都擁有 Error 的特性:有錯(cuò)誤消息、有調(diào)用棧、有方便打印的 toString 等。,需要的朋友可以參考下
    2019-06-06
  • JavaScript深入V8引擎以及編寫優(yōu)化代碼的5個(gè)技巧

    JavaScript深入V8引擎以及編寫優(yōu)化代碼的5個(gè)技巧

    這篇文章主要介紹了JavaScript深入V8引擎以及編寫優(yōu)化代碼的5個(gè)技巧,JavaScript引擎是執(zhí)行 JavaScript 代碼的程序或解釋器。JavaScript引擎可以實(shí)現(xiàn)為標(biāo)準(zhǔn)解釋器,或者以某種形式將JavaScript編譯為字節(jié)碼的即時(shí)編譯器。,需要的朋友可以參考下
    2019-06-06
  • JavaScript中DOM尺寸測量與節(jié)流技巧總結(jié)

    JavaScript中DOM尺寸測量與節(jié)流技巧總結(jié)

    在網(wǎng)頁開發(fā)中,合理獲取DOM元素尺寸及使用節(jié)流技術(shù)對高頻事件進(jìn)行優(yōu)化,是確保頁面流暢運(yùn)行的關(guān)鍵,通過JavaScript可以方便地獲取元素寬高,并應(yīng)用節(jié)流(Throttle)與防抖(Debounce)技術(shù)處理如滾動或窗口調(diào)整等高頻事件,有效減少性能消耗,需要的朋友可以參考下
    2024-11-11

最新評論

高淳县| 昔阳县| 子洲县| 县级市| 临城县| 左权县| 彭泽县| 韩城市| 临漳县| 彰化市| 包头市| 阿合奇县| 福贡县| 云浮市| 曲阳县| 阜平县| 绿春县| 汤阴县| 绩溪县| 合水县| 中宁县| 同德县| 万盛区| 昌平区| 贵溪市| 福贡县| 临漳县| 南汇区| 五指山市| 略阳县| 阿尔山市| 京山县| 苍溪县| 绥德县| 天台县| 新昌县| 确山县| 青铜峡市| 如东县| 邳州市| 安达市|