1. 程式人生 > >JavaScript中的事件冒泡與捕獲

JavaScript中的事件冒泡與捕獲

事件冒泡和事件捕獲分別由微軟和網景公司提出,這兩個概念都是為了解決頁面中事件流(事件發生順序)的問題。
考慮下面這段程式碼

<div id="outer">
    <p id="inner">Click me!</p>
</div>

上面的程式碼當中一個div元素當中有一個p子元素,如果兩個元素都有一個click的處理函式,那麼我們怎麼才能知道哪一個函式會首先被觸發呢?
為了解決這個問題微軟和網景提出了兩種幾乎完全相反的概念。

事件冒泡

微軟提出了名為事件冒泡(event bubbling)的事件流。事件冒泡可以形象地比喻為把一顆石頭投入水中,泡泡會一直從水底冒出水面。也就是說,事件會從最內層的元素開始發生,一直向上傳播,直到document物件。

因此在事件冒泡的概念下在p元素上發生click事件的順序應該是p -> div -> body -> html -> document

事件捕獲

網景提出另一種事件流名為事件捕獲(event capturing)。與事件冒泡相反,事件會從最外層開始發生,直到最具體的元素。

因此在事件捕獲的概念下在p元素上發生click事件的順序應該是document -> html -> body -> div -> p

addEventListener的第三個引數

網景 和 微軟 曾經的戰爭還是比較火熱的,當時, 網景主張捕獲方式,微軟主張冒泡方式。後來 w3c 採用折中的方式,平息了戰火,制定了統一的標準——先捕獲再冒泡。
addEventListener的第三個引數就是為冒泡和捕獲準備的.
addEventListener有三個引數:

element.addEventListener(event, function, useCapture)
  • 第一個引數是需要繫結的事件
  • 第二個引數是觸發事件後要執行的函式
  • 第三個引數預設值是false,表示在事件冒泡階段呼叫事件處理函式;如果引數為true,則表示在事件捕獲階段呼叫處理函式。

冒泡的案例

<div id="s1">s1
    <div id="s2">s2</div>
</div>
<script>
    s1.addEventListener("click",function(e){
        console.log("s1 冒泡事件"
); },false); s2.addEventListener("click",function(e){ console.log("s2 冒泡事件"); },false);
</script>

當我們點選s2的時候,執行結果如下:
s2 冒泡事件
s1 冒泡事件

捕獲的案例

<div id="s1">s1
    <div id="s2">s2</div>
</div>
<script>
    s1.addEventListener("click",function(e){
        console.log("s1 捕獲事件");
    },true);
    s2.addEventListener("click",function(e){
        console.log("s2 捕獲事件");
    },true);
</script>

當我們點選s2的時候,執行結果如下:
s1 捕獲事件
s2 捕獲事件

事件捕獲vs事件冒泡

當事件捕獲和事件冒泡一起存在的情況,事件又是如何觸發呢。
這裡記被點選的DOM節點為target節點

  • document 往 target節點,捕獲前進,遇到註冊的捕獲事件立即觸發執行
  • 到達target節點,觸發事件(對於target節點上,是先捕獲還是先冒泡則捕獲事件和冒泡事件的註冊順序,先註冊先執行)
  • target節點 往 document 方向,冒泡前進,遇到註冊的冒泡事件立即觸發

    總結下就是:

  • 對於非target節點則先執行捕獲在執行冒泡
  • 對於target節點則是先執行先註冊的事件,無論冒泡還是捕獲
 <div id="s1">s1
    <div id="s2">s2</div>
</div>
<script>
s1.addEventListener("click",function(e){
        console.log("s1 冒泡事件");         
},false);
s2.addEventListener("click",function(e){
        console.log("s2 冒泡事件");
},false);

s1.addEventListener("click",function(e){
        console.log("s1 捕獲事件");
},true);

s2.addEventListener("click",function(e){
        console.log("s2 捕獲事件");
},true);
</script>

當我們點選s2的時候,執行結果如下:
s1 捕獲事件
s2 冒泡事件
s2 捕獲事件
s1 冒泡事件

這裡大體分析下執行結果

  1. 點選s2,click事件從document->html->body->s1->s2(捕獲前進)
  2. 這裡在s1上發現了捕獲註冊事件,則輸出”s1 捕獲事件”
  3. 到達s2,已經到達目的節點,
  4. s2上註冊了冒泡和捕獲事件,先註冊的冒泡後註冊的捕獲,則先執行冒泡,輸出”s2 冒泡事件”
  5. 再在s2上執行後註冊的事件,即捕獲事件,輸出”s2 捕獲事件”
  6. 下面進入冒泡階段,按照s2->s1->body->html->documen(冒泡前進)
  7. 在s1上發現了冒泡事件,則輸出”s1 冒泡事件”

事件冒泡與事件捕獲應用:事件代理

在實際的開發當中,利用事件流的特性,我們可以使用一種叫做事件代理的方法。

<ul id="color-list">
    <li>red</li>
    <li>yellow</li>
    <li>blue</li>
    <li>green</li>
    <li>black</li>
    <li>white</li>
</ul>

如果點選頁面中的li元素,然後輸出li當中的顏色,我們通常會這樣寫:

(function(){
    var color_list = document.getElementById('color-list');
    var colors = color_list.getElementsByTagName('li');
    for(var i=0;i<colors.length;i++){                          
        colors[i].addEventListener('click',showColor,false);
    };
    function showColor(e){
        var x = e.target;
        console.log("The color is " + x.innerHTML);
    };
})();

利用事件流的特性,我們只繫結一個事件處理函式也可以完成:

(function(){
    var color_list = document.getElementById('color-list');
    color_list.addEventListener('click',showColor,false);
    function showColor(e){
        var x = e.target;
        if(x.nodeName.toLowerCase() === 'li'){
            console.log('The color is ' + x.innerHTML);
        }
    }
})();

使用事件代理的好處不僅在於將多個事件處理函式減為一個,而且對於不同的元素可以有不同的處理方法。假如上述列表元素當中添加了其他的元素(如:a、span等),我們不必再一次迴圈給每一個元素繫結事件,直接修改事件代理的事件處理函式即可。

冒泡還是捕獲?

對於事件代理來說,在事件捕獲或者事件冒泡階段處理並沒有明顯的優劣之分,但是由於事件冒泡的事件流模型被所有主流的瀏覽器相容,從相容性角度來說還是建議大家使用事件冒泡模型。

相關推薦

JavaScript事件冒泡捕獲

事件冒泡和事件捕獲分別由微軟和網景公司提出,這兩個概念都是為了解決頁面中事件流(事件發生順序)的問題。 考慮下面這段程式碼 <div id="outer"> <p id="inner">Click me!</p>

JS 基礎篇(六):事件冒泡捕獲

目錄: 一、事件冒泡 微軟提出了名為事件冒泡(event bubbling)的事件流。事件冒泡可以形象地比喻為把一顆石頭投入水中,泡泡會一直從水底冒出水面。也就是說,事件會從最內層的元素開始發生,一直向上傳播,直到document物件。 <html>

關於JS事件捕獲事件冒泡事件代理(事件委託),及e.targete.currentcurrentTarget的區別

事件捕獲:        表示事件的觸發順序,當繫結事件方法的第三個引數值設定為true時,事件觸發的順序為捕獲。        當一個元素的事件被觸發的時候(如onclick事件),該事件會從document開

js 事件冒泡事件捕獲

nodename 瀏覽器兼容 而不是 rop 希望 bubble lis 彈出 element 一、事件冒泡 事件冒泡是指在事件發生過程中先從目標節點開始執行,並一層一層的相父節點依次查詢直到document,並執行相同事件的過程。 btn1.addEventListe

JS事件冒泡事件捕獲

簡單理解: 事件冒泡:頁面上有這麼一個節點樹,div>ul>li>a;比如給最裡面的a加一個click點選事件,那麼這個事件就會一層一層的往外執行,執行順序a>li>ul>div,即自下而上觸發事件。 事件捕獲: 跟上面的正好相反,自上而下觸發事

簡單的理解事件冒泡事件捕獲

例如下面的圖中外面的綠色的框為父級(parent),裡面的橙色框為子級(child) var parent = document.getElementsByClassName("block_P")[0]; var child = document.ge

冒泡捕獲事件繫結,阻止事件冒泡,阻止預設行為

Internet Explorer 8 及更早IE版本不支援 addEventListener() 方法,Opera 7.0 及 Opera 更早版本也不支援。 但是,對於這些不支援該函式的瀏覽器,你可以使用 attachEvent() 方法來新增事件控制代碼。對於事件繫結相

JavaScript事件的相容(事件的繫結addEventListener/移除removeEventListener,阻止冒泡/預設)

一.事件相容 1.事件繫結:addEventListener 用於註冊事件處理程式(為文件節點).IE 中為 attachEvent,我們為 什麼講addEventListener而不講attachEvent呢?一來attachEvent比較簡單,二來addEventListener才是

JS 入門教程-16-addEventListener,removeEventListener,事件冒泡事件捕獲

事件監聽 addEventListener 說明 新增事件監聽 語法 element.addEventListener(event, function, useCapture); 第一個引數是事件的型別 (如 “click” 或 “m

面試題-冒泡捕獲事件委託、ie事件和dom模型事件、滑鼠事件

    一直沒有搞懂jquery中的事件是怎麼新增事件處理程式的。原來就是用了事件委託,關鍵就是通過冒泡方式實現在最高層(document)處理事件,通過判斷事件target的id,給以不同的handler。當然也可以通過事件捕獲來處理,但是因為ie中只有冒泡,所以還是用

滑鼠事件冒泡捕獲

需求 當滑鼠劃過導航欄中某一選單項時,顯示其完整子選單;滑鼠移動出該選單項及其對應的子選單時,延遲0.5s子選單消失。 思路 首先,將子選單#sub-menu設定為display:none;並且在選單項及其子選單項的工頭父元素#nav上繫結事件:

javascript事件對象註冊刪除

ie8 ply 設置 als google 一個 標簽設置 this ... 事件對象 註冊事件 直接給dom對象設置屬性,只能給對象設置一個屬性,如果設置多個事件處理函數,則最後的生效; 給html標簽設置屬性,(若法1和法2同時使用,則法1生效); 事件註冊 綁定事件

聊聊事件冒泡事件捕獲

cto fine mage 開始 表示 nload font on() his 什麽是事件?   事件是文檔和瀏覽器窗口中發生的特定的交互瞬間。 什麽是事件流: 事件流描述的是從頁面中接受事件的順序( 說白了就是解決頁面中事件流發生順序的問題。),但有意思的是

javascript的undefinedis not defined

ole 返回 對象 javascrip efi {} define var bsp 1. var a; console.log(a); 這裏打印的是undefined; 2. console.log(b); 這裏瀏覽器會報錯,b is not defined; 3. var

Javascript的applycall詳解

選項 this 模式 div sun fun object 面向 傳遞     JavaScript中有一個call和apply方法,其作用基本相同,但也有略微的區別。  一、方法定義   1、call 方法   語法:call([thisObj[,arg1[, arg2[

JavaScript的nullnudefined

設置 同時 scrip script ogl 效果 報告 object 數字 null和undefined 作者總結: null在進行數字運算時可以轉換成0,而undefined會被轉換成NaN(歷史原因); 另外用typeof檢測null會返回object對象類型 註

javascript的addEventListenerattchEvent

不支持 func 瀏覽器 元素 由於 ie9 bsp apt 指定元素 1、addEventListener 該方法用於向指定元素添加事件句柄 瀏覽器的支持情況為chrome1.0、ie9+、fireFox1.0、opera7.0 該方法包含三個參數event, fu

javascript冒泡排序法

沒有 使用 排列 10個 應該 初始 pan 十個 二次 在開發中,對一組數據進行有序地排列是經常需要做的事情,所以掌握幾種甚至更多的排序算法是絕對有必要的 這裏要介紹的是排序算法中較簡單的一種算法:冒泡排序。 先嘗試用最簡單的想法去實現排序,以此來比較學習

javascript阻止事件冒泡和瀏覽器的默認行為

pre stop key else can put 事件冒泡 prop top 1.阻止事件冒泡,使成為捕獲型事件觸發機制. 1 function stopBubble(e) { 2 //如果提供了事件對象,則這是一個非IE瀏覽器 3 if ( e &&

JavaScript事件的target屬性

button name 點擊事件 .html hasclass alert -c color min target 事件屬性可返回事件的目標節點(哪個 DOM 元素觸發了該事件),如生成事件的元素、文檔或窗口。 語法:event.target <html> &