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 冒泡事件
這裡大體分析下執行結果
- 點選s2,click事件從document->html->body->s1->s2(捕獲前進)
- 這裡在s1上發現了捕獲註冊事件,則輸出”s1 捕獲事件”
- 到達s2,已經到達目的節點,
- s2上註冊了冒泡和捕獲事件,先註冊的冒泡後註冊的捕獲,則先執行冒泡,輸出”s2 冒泡事件”
- 再在s2上執行後註冊的事件,即捕獲事件,輸出”s2 捕獲事件”
- 下面進入冒泡階段,按照s2->s1->body->html->documen(冒泡前進)
- 在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.target與e.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中的undefined與is 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中的apply與call詳解
選項 this 模式 div sun fun object 面向 傳遞 JavaScript中有一個call和apply方法,其作用基本相同,但也有略微的區別。 一、方法定義 1、call 方法 語法:call([thisObj[,arg1[, arg2[
JavaScript中的null與nudefined
設置 同時 scrip script ogl 效果 報告 object 數字 null和undefined 作者總結: null在進行數字運算時可以轉換成0,而undefined會被轉換成NaN(歷史原因); 另外用typeof檢測null會返回object對象類型 註
javascript中的addEventListener與attchEvent
不支持 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> &