完全搞懂JS事件冒泡與捕獲

事件冒泡與事件捕獲

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

以下:假設三層div都有事件監聽,這時咱們點擊的小的藍方框,事件執行的順序是怎麼樣的呢html

<div id="s1" style="height: 400px;width: 400px;border: 1px solid red">紅
    <div id="s2" style="height: 200px;width: 200px;border: 1px solid yellow">
        黃
        <div id="s3" style="height: 100px;width: 100px;border: 1px solid blue">藍</div>
    </div>
</div>

事件冒泡

微軟提出了名爲事件冒泡(event bubbling)的事件流。事件冒泡能夠形象地比喻爲把一顆石頭投入水中,泡泡會一直從水底冒出水面。也就是說,事件會從最內層的元素開始發生,一直向上傳播,直到document對象。
所以在事件冒泡的概念下在div元素上發生click事件的順序應該是div -> body -> html -> documentjava

事件捕獲

網景提出另外一種事件流名爲事件捕獲(event capturing)。與事件冒泡相反,事件會從最外層開始發生,直到最具體的元素。
所以在事件捕獲的概念下在div元素上發生click事件的順序應該是document -> html -> body -> div -> div瀏覽器

w3c 採用折中的方式,制定了統一的標準——先捕獲再冒泡。

addEventListener第三個參數默認值是false,表示在事件冒泡階段調用事件處理函數;若是參數爲true,則表示在事件捕獲階段調用處理函數。函數

測試事件冒泡-點擊藍色

s1 = document.getElementById('s1')
    s2 = document.getElementById('s2')
    s3 = document.getElementById('s3')

    s1.addEventListener("click",function(e){
        console.log("紅 冒泡事件");//從底層往上
    },false);//第三個參數默認值是false,表示在事件冒泡階段調用事件處理函數;若是參數爲true,則表示在事件捕獲階段調用處理函數。
    s2.addEventListener("click",function(e){
        console.log("黃 冒泡事件");
    },false);
    s3.addEventListener("click",function(e){
        console.log("藍 冒泡事件");
    },false);

測試事件捕獲-點擊藍色

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

    s2.addEventListener("click",function(e){
        console.log("黃 捕獲事件");

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

事件捕獲與事件冒泡同時存在-先捕獲後冒泡

  • 這裏記被點擊的DOM節點爲target節點,document 往 target節點,捕獲前進,遇到註冊的捕獲事件當即觸發執行
  • 到達target節點,觸發事件
  • 對於target節點上,是先捕獲仍是先冒泡則捕獲事件和冒泡事件的註冊順序,先註冊先執行
  • arget節點 往 document 方向,冒泡前進,遇到註冊的冒泡事件當即觸發

s1.addEventListener("click",function(e){
        console.log("紅 冒泡事件");
    },false);
    s2.addEventListener("click",function(e){
        console.log("黃 冒泡事件");
    },false);
    s3.addEventListener("click",function(e){
        console.log("藍 冒泡事件");
    },false);

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

    s2.addEventListener("click",function(e){
        console.log("黃 捕獲事件");

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

應用:事件委託(也叫事件代理)

好比我想點擊ul標籤裏面的li獲取它的值,有點人就會遍歷去給每一個li加一個事件監聽
其實咱們能夠在li的父級加一個事件監聽,這就至關於把事件監聽委託給了ul
咱們點擊li的時候是會打出值的測試

<ul id="ul">
    <li>1</li>
    <li>2</li>
    <li>3</li>
    <li>4</li>
    <li>5</li>
    <li>6</li>
    <li>7</li>
</ul>
ul = document.getElementById('ur')

    ul.addEventListener("click",function(e){
        console.log(e.target.innerText);
    },false);

onclick事件分析

onclick不能像addEventListener那樣指定是事件類型,它只能是事件冒泡spa

s1.onclick=function(){
        console.log('紅')
    }
    s2.onclick=function(){
        console.log('黃')
    }
    s3.onclick=function(){
        console.log('藍')
        return true
    }

阻止事件冒泡和事件默認行爲

但某一些時候咱們不想觸發事件冒泡怎麼辦或者是不想觸發默認的一些方法代理

e.stopPropagation()

這是W3C的標準方法,stopPropagation是事件對象(Event)的一個方法,做用是阻止目標元素的冒泡事件,可是會不阻止默認行爲。
IE使用的是IE則是使用e.cancelBubble = truecode

function stopBubble(e) { 
//若是提供了事件對象,則這是一個非IE瀏覽器 
if ( e && e.stopPropagation ) 
    //所以它支持W3C的stopPropagation()方法 
    e.stopPropagation(); 
else 
    //不然,咱們須要使用IE的方式來取消事件冒泡 
    window.event.cancelBubble = true; 
}

e.preventDefault()

preventDefault它是事件對象(Event)的一個方法,做用是取消一個目標元素的默認行爲。既然是說默認行爲,固然是元素必須有默認行爲才能被取消,若是元素自己就沒有默認行爲,調用固然就無效了。什麼元素有默認行爲呢?如連接<a>,提交按鈕<input type=」submit」>等。當Event 對象的 cancelable爲false時,表示沒有默認行爲,這時即便有默認行爲,調用preventDefault也是不會起做用的。htm

return false

javascript的return false只會阻止默認行爲,而是用jQuery的話則既阻止默認行爲又防止對象冒泡。

//阻止瀏覽器的默認行爲 總結
function stopDefault( e ) { 
    //阻止默認瀏覽器動做(W3C) 
    if ( e && e.preventDefault ) 
        e.preventDefault(); 
    //IE中阻止函數器默認動做的方式 
    else 
        window.event.returnValue = false; 
    return false; 
}
相關文章
相關標籤/搜索