天天看點

在js中事件冒泡的了解分析

一. 事件

  1. 事件的三個階段:事件捕獲 -> 事件目标 -> 事件冒泡

    捕獲階段:先由文檔的根節點document往事件觸發對象,從外向内捕獲事件對象;

    目标階段:到達目标事件位置(事發地),觸發事件;

    冒泡階段:再從目标事件位置往文檔的根節點方向回溯,從内向外冒泡事件對象

  2. 事件捕獲:事件發生時首先發生在document上,然後依次傳遞給body,最後到達目的節點(即事件目标),事件流模型:div →body→ html→ document 。

    圖示說明:

    在js中事件冒泡的了解分析
  3. 事件冒泡:事件到達事件目标之後不會結束,會逐層向上冒泡,直至document對象,跟事件捕獲相反。

    圖示說明:

    在js中事件冒泡的了解分析
  4. onclick 事件冒泡,重寫onlick會覆寫之前屬性,沒有相容性問題

    addEventListener(event.type, handle, boolean); IE8及以下不支援,屬于DOM2級的方法,可添加多個方法不被覆寫。事件類型沒有on,第三個參數false,表示在事件第三階段(冒泡)觸發,true表示在事件第一階段(捕獲)觸發。如果綁定同一個事件同一個方法,隻會執行一次,是以如果handle是同一個方法,隻執行一次。

    attachEvent(event.type, handle ); IE特有,相容IE8及以下,可添加多個事件處理程式,隻支援冒泡階段,可以多次進行綁定,是以如果handle是同一個方法,綁定幾次執行幾次,同時事件類型要加on。

    預設事件行為:href="" target="_blank" rel="external nofollow" 連結,submit表單送出等

  5. 阻止預設事件:

    return false; 阻止獨享屬性(通過on這種方式)綁定的事件的預設事件,阻止浏覽器對事件的預設處理,隻在目前函數有效,不會影響其他外部函數的執行

    event.preventDefault( ); 阻止通過 addEventListener( ) 添加的事件的預設事件

    event.returnValue = false; 阻止通過 attachEvent( ) 添加的事件的預設事件

  6. 事件的綁定與事件的解綁

    事件的綁定:

    代碼如下:

function addEvent(element,eType,handle,bol){
        //  支援addEventListener
        if(element.addEventListener){
            element.addEventListener(eType,handle,bol);
        //  支援attachEvent
        }else if(element.attachEvent){
            element.attachEvent("on"+eType,handle);
        //  相容的onclick的綁定
        }else{
            element["on"+eType] = handle;
        }
    }
           

事件的解綁:

代碼如下:

function removeEvent(element,eType,handle,bol){
        // 支援addEventListener
        if(element.addEventListener){
            element.addEventListener(eType,handle,bol);
       //  支援attachEvent
        }else if(element.attachEvent){
            element.detachEvent("on"+eType,handle);
       //  相容的onclick的綁定
        }else{
            element["on"+eType] = null;
        }
    }
           

封裝函數:通過事件冒泡的方式,相容事件捕獲隻需要添加個bool參數

代碼如下:

var EventUtil = {
         addEvent: function(element,type,handle){
             if(element.addEventListener){
                 element.addEventListener(type,handle,false);
             }else if(element.addEvent){
                 element.addEvent("on"+type,handle);
             }else{
                 element["on"+type] =  handle;
             }
         },

        removeEvent:function(element,type,handle){
            if(element.removeEventListener){
                element.removeEventListener(type,handle,false);
            }else if(element.removeEvent){
                element.removeEvent("on"+type,handle);
            }else{
                element["on"+type] = null;
            }
        }
        
    }
           
  1. 常見的事件綁定

    1)bind()

    隻能給調用它的時候已經存在的元素綁定事件,不能給未來新增的元素綁定事件

    bind()不能使用的情況:為DOM中的很多元素綁定相同的事件,為DOM中的尚不存在的元素綁定事件

    2)live()

    方法會把click事件綁定到(document)對象,而且隻需要給(document)綁定一次,然後就能夠處理後續動态加載的節點的事件

    在接收到任何事件時,(document)對象都會檢查事件類型和事件目标,如果是click事件且事件目标是td,那麼就執行委托給它的處理程式

    3)delegate()

    直接将目标元素選擇符(“td”)、事件(“click”)及處理程式與“受拖方”("#info_table")綁定,不額外收集元素、事件傳播路徑縮短、語義明确

    支援在連綴的DOM周遊方法後面調用

  2. 事件冒泡、事件捕獲阻止

    event.stopPropagation( ); 阻止事件的進一步傳播,包括(冒泡,捕獲),無參數

    event.cancelBubble = true; true 為阻止冒泡

  3. W3C事件模型中發生的任何事件,先從其祖先元素window開始一路向下捕獲, 直到達到目标元素,其後再次從目标元素開始冒泡。可以決定事件處理器是注冊在捕獲或者是冒泡階段。

    注意:如果addEventListener的最後一個參數是true, 那麼處理函數将在捕獲階段被觸發; 否則(false), 會在冒泡階段被觸發,預設false。

二、事件冒泡

  1. 事件冒泡:當一個元素接收到事件的時候 會把他接收到的事件傳給自己的父級,一直到window。從事件源,自下而上的過程中,阻止向上冒泡,即阻止觸發上級元素的事件觸發,上級元素做事件觸發時,在此事件源上無效。在事件傳播的過程中,當事件在一個元素上出發之後,事件會逐級傳播給先輩元素,直到document為止,有的浏覽器可能到window為止。
  2. 事件冒泡的執行個體

    代碼如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>事件冒泡</title>
</head>
<body>

<div id="div1">div1
    <div id="div2">div2</div>
</div>

</body>
<script>

    var div1 = document.getElementById("div1");
    var div2 = document.getElementById("div2");

    div1.onclick = function(){
        console.log("我是div1");
    };

    div2.onclick = function(){
        console.log("我是div2");
    };

</script>
</html>
           

說明:兩個父子關系的div1和div2,分别給div1和div2綁定了點選事件。當點選div1的時候,控制台列印輸出 我是div1。當點選div2的時候,控制台列印輸出 我是div2 和 我是div1,在這個時候就說明了當我們子點選div2的時候,div1的事件也被觸發了,父級事件被觸發,這種現象相當于就是冒泡事件。

  1. 取消事件冒泡的方式:

    标準的W3C 方式:e.stopPropagation();這裡的stopPropagation是标準的事件對象的一個方法,調用即可

    非标準的IE方式:ev.cancelBubble=true; 這裡的cancelBubble是 IE事件對象的屬性,設為true就可以了

    封裝取消事件冒泡的函數:

    代碼如下:

function stopBubble(env){
        // 如果提供事件對象,說明為非IE浏覽器
        if(env && env.stopPropagation){
            env.stopPropagation();
        }else{
         // IE浏覽器
            window.event.cancelBubble = true;
        }
    }
           
  1. 取消事件冒泡的執行個體:

    代碼如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>事件冒泡2</title>
    <style>
        .d1 {
            width: 300px;
            height: 300px;
            background-color: skyblue;
            display: none;
        }

    </style>
</head>
<body>

<button id="btn">按鈕</button>
<div class="d1"></div>

</body>
<script>

    // 單擊動作會從btn傳到document中,發生事件冒泡

    var btn = document.getElementById("btn");
    var d1 = document.getElementsByClassName("d1")[0];

    // 點選按鈕的時候,元素d1顯示
    btn.onclick = function(e){
        d1.style.display = "block";
        // 阻止冒泡
        stopBubble(e);
    };

    // 點選網頁其它地方的時候,元素d1隐藏
    document.onclick = function(){
        d1.style.display = "none";
    };

    // 阻止浏覽器的預設行為函數,事件冒泡
    //  event.stopPropagation   阻止事件冒泡的方法
    function stopBubble(e) {
        // 非IE浏覽器阻止冒泡
        if( e && e.stopPropagation )
            e.stopPropagation();
        else
        // IE浏覽器阻止冒泡
           window.event.cancelBubble = true;
    }

</script>
</html>
           

說明:定義一個按鈕,在按鈕下面有一個div的元素d1,預設為隐藏。點選按鈕的時候,元素d1顯示。在點選按鈕的時候,調用了阻止事件冒泡的發生函數stopBubble()。點選docume網頁其它地方的時候,元素d1隐藏。

三、跨浏覽器的事件對象

  1. 跨浏覽器的事件對象

    代碼如下:

var EventUtil={
    getEvent:function(event){
        return event||window.event;
    },
    getTarget:function(event){
        return event.target||event.srcElement;
    },
    preventDefault:function(){
        if(event.preventDefault){
            event.preventDefault();
        }else{
            event.returnValue=false;
        }
    },
    stopPropagation:function(){
        if(event.stopPropagation){
            event.stopPropagation();
        }else{
            event.cancelBubble=true;
        }
    },
    addEvent:function(element,type,handler){
        if(element.addEventListener){
            element.addEventListener(type,handler,false);
        }else if(element.attachEvent){
             element["e"+type]=function(){
              handler.call(element)
          }
            element.attachEvent("on"+type,element["e"+type]);
        }else{
            element["on"+type]=handler;
        }
    },
    removeEvent:function(element,type,handler){
        if(element.removeEventListener){
            element.removeEventListener(type,handler,false);
        }else if(element.detachEvent){
            element.detachEvent("on"+type,element["e"+type]);
            element["e"+type]=null;    
        }else{
            element["on"+type]=null;
        }
    }

  };
           

繼續閱讀