1. 程式人生 > >javascript冒泡事件詳解

javascript冒泡事件詳解

event prop -h round bracket 同時 load 回調 str

  • 冒泡事件

    定義:當多個Dom元素互相嵌套的時候,一個元素觸發了某個事件(例如Click事件),那麽嵌套此事件的所有元素都會被觸發一次Click事件,註意:只會觸發他的直系親屬元素,而與其自己,父級,爺級等等同級的親戚集是不會觸發的

  • 捕獲事件:

    *定義:** 同冒泡事件含義相似,只是將冒泡事件的觸發順序倒過來即可

  • DOM事件流

    元素的觸發流程分為三個階段

    1. 捕獲階段:先從祖先級一直找到觸發的源元素(所有元素都觸發了相同事件)

    2. 目標階段:找到原元素,然後觸發源元素的事件

    3. 冒泡階段:然後重新流回祖先元素,又觸發了一遍相同事件

  • 思考: 按照上面的事件流,豈不是一個元素會觸發兩次事件?那這不是很奇怪嗎:其實在我們一般開發過程中都是用Jqueryon 方法來綁定的(推薦使用),綁定後,只會觸發冒泡事件。那麽什麽時候會涉及到這個捕獲階段呢,在原生的javascript中,就會有此方法的使用,且看下面詳解

  • 詳解 addEventListener/removeEventListener

    作用: 原生的事件綁定方法

    ?
    // type:事件類型,不含"on",比如"click"、"mouseover"、"keydown";
    // 而attachEvent的事件名稱,含含"on",比如"onclick"、"onmouseover"、"onkeydown";
    // listener:事件處理函數
    // useCapture是事件冒泡,還是事件捕獲(true),默認false,代表事件冒泡類型
    addEventListener(type, listener, useCapture);

    特點:

    1. 一個元素可以同時綁定兩種類型(捕獲/冒泡)

    2. 一個同種類型的元素重復綁定同一個事件函數,只綁定一次

    3. 一個元素可以重復綁定多個不同的函數,且是疊加而非覆蓋

  • 觸發流程:

    1. 首先源目標觸發了事件

    2. 開始捕獲階段,將其直系親屬(類型為捕獲)的事件觸發

    3. 到達源元素,觸發事件方法,如果重復綁定多個,則按綁定順序觸發(源元素的類型其實沒有影響)

    4. 然後開始冒泡排序,將其直系親屬(類型為冒泡)的事件觸發

    <script>

    window.onload = function(){
    var outA = document.getElementById("outA");
    var outB = document.getElementById("outB");
    var outC = document.getElementById("outC");

    // 目標(自身觸發事件,是冒泡還是捕獲無所謂)
    outC.addEventListener(‘click‘,function(){alert("target2");},true);
    outC.addEventListener(‘click‘,function(){alert("target1");},true);

    // 事件冒泡
    outA.addEventListener(‘click‘,function(){alert("bubble1");},false);
    outB.addEventListener(‘click‘,function(){alert("bubble2");},false);

    // 事件捕獲
    outA.addEventListener(‘click‘,function(){alert("capture1");},true);
    outB.addEventListener(‘click‘,function(){alert("capture2");},true);
    };

    </script>

    <body>
    <div id="outA" style="width:400px; height:400px; background:#CDC9C9;position:relative;">
    <div id="outB" style="height:200; background:#0000ff;top:100px;position:relative;">
    <div id="outC" style="height:100px; background:#FFB90F;top:50px;position:relative;"></div>
    </div>
    </div>
    </body>
    ?
    點擊outC的時候,打印順序是:capture1-->capture2-->target2-->target1-->bubble2-->bubble1

    結論:捕獲階段的處理函數最先執行,其次是目標階段的處理函數,最後是冒泡階段的處理函數。目標階段的處理函數,先註冊的先執行,後註冊的後執行

  • 如何解決冒泡/捕獲事件的影響

    目的: 我們很清楚,解決冒泡和捕獲事件的影響,只需要在源元素觸發完事件之後停止事件的傳播即可

    方式:

    1. event.stopPropagation(); 只阻止了冒泡事件, 默認行為沒有阻止(超鏈接a嵌套按鈕,依然會跳轉)

    2. event.preventDefault(); 只阻止了默認事件,冒泡事件沒有阻止(超鏈接a嵌套按鈕,不跳轉,但會觸發點擊事件)

    3. return false; 冒泡事件和默認事件都阻止

    <script>

    window.onload = function(){
    var outA = document.getElementById("outA");
    var outB = document.getElementById("outB");
    var outC = document.getElementById("outC");

    // 目標
    outC.addEventListener(‘click‘,function(event){
    alert("target");
    event.stopPropagation();
    },false);

    // 事件冒泡
    outA.addEventListener(‘click‘,function(){alert("bubble");},false);

    // 事件捕獲
    outA.addEventListener(‘click‘,function(){alert("capture");},true);

    };

    </script>

    <body>
    <div id="outA" style="width:400px; height:400px; background:#CDC9C9;position:relative;">
    <div id="outB" style="height:200; background:#0000ff;top:100px;position:relative;">
    <div id="outC" style="height:100px; background:#FFB90F;top:50px;position:relative;"></div>
    </div>
    </div>
    </body>
    capture-->target,不會打印出bubble。因為當事件傳播到outC上的處理函數時,通過stopPropagation阻止了事件的繼續傳播,所以不會繼續傳播到冒泡階段,當然如果此方法放到了捕獲中,那麽就只會打印出capture了
  • 註意點:

    今天用 on 綁定的時候,div 嵌套按鈕,按鈕裏的事件觸發帶有ajax的請求,結果點擊確實進入了按鈕事件方法中,但是還沒有進入回調函數,就跳轉到div的點擊事件方法中了,然後再跳回回調方法中,采用了以下方法解決

    ?
    <html>
    <head>
    <meta name="viewport" content="width=device-width" />
    <title>webApi測試</title>
    <script src="~/js/jquery.min.js"></script>
    </head>
    <body>
    <div id="first">
    </div>
    <div id="outA" style="width:400px; height:400px; background:#CDC9C9;position:relative;">
    <div id="outB" style="height:200; background:#0000ff;top:100px;position:relative;">
    <div id="outC" style="height:100px; background:#FFB90F;top:50px;position:relative;"></div>
    </div>
    </div>
    </div>
    </body>
    </html>
    ?
    <script>
    $(function () {
    ?
    $("#outC").on ("click",function () { alert("C")});
    $("#outB").on ("click",function () { alert("B") });
    $("#outA").on("click", function () { alert("A") });
    $("#outD").on("click", function () { alert("D") });
    ?
    $("#first").on("click", function () { debugger; alert("最外層div") });
    $("#routeTest").on("click", ajaxFunction);
    ?
    function ajaxFunction() {
    debugger;
    //event.cancelBubble = true;//取消事件的冒泡,效果同下
    //return false//此方法會導致此方法直接結束,因此不能直接使用
    event.stopPropagation();
    $.ajax({
    url: "/Course/GetCourseByRoute?temp"+Date.parse(new Date()),
    type: ‘get‘,
    success: function (res) {
    debugger;
    alert(res);
    }
    });
    }
    });
    </script>

  • 參考資料

    1. 冒泡捕獲

    2. 阻止冒泡事件及應對動態綁定元素的註意點

javascript冒泡事件詳解