JS事件捕獲與冒泡

先解釋下事件捕獲和冒泡:
捕獲—事件從最上一級標籤開始往下查找,直到捕獲到事件目標(target)
冒泡—事件從事件目標(target)開始,往上冒泡直到頁面的最上一級標籤。

在嵌套很多層的情況下, 如下:

html
<div class="div1" onclick="outer();">
    <div class="div2" onclick="middle();">
        <div class="div3" onclick="inner();"></div>
    </div>
</div>
css
.div1{width:300px;height:300px;border:1px solid red;}
.div2{width:200px;height:200px;border:1px solid green;}
.div3{width:100px;height:100px;border:1px solid blue;}
js
function html(){alert("html");} //加在html的onclick方法
function body1(){alert("body");}//加在body的onclick方法
function outer(){alert("outer");}
function middle(){alert("middle");}
function inner(){alert("inner");}
window.addEventListener("click", function(){alert("window");}) //加在window的onclick方法

當點擊最深層的div3後,彈框順序:
inner->middle->outer->body->html->window
網上有人說到body之後直接跳到window,但測試之後發現還是要到html,而window作爲頂層對象,自然壓軸登場(冒泡順序和瀏覽器有關).所以由此看出, 事件冒泡機制是從裏向外. 自然, 阻止冒泡也是有辦法的, 如下:
當把function inner寫成如下時,

function inner(e){
    alert("inner");
    e=e?e:event; //兼容低版本火狐
    // 阻止冒泡
    if(e.stopPropagation){ //webkit內核
        e.stopPropagation();
    }else{
        e.cancelBubble=true; //兼容IE9(含)以下
    }
}

再點擊div inner, 彈框順序是: inner;
是的, 只有一個彈框, 因爲onclick事件默認是冒泡的順序, 所以阻止冒泡後, 附加在目標(target)父級的點擊方法全都不執行.
再進行測試, 如果採用捕獲機制(這隻在DOM3級事件纔有—addEventListener), 所以我們對window綁定的點擊事件進行改進, 不過在此之前, 我們先對addEventListener有更進一步的瞭解:

target.addEventListener(eventType, callback, isnotBubble);
/***
 *
 * eventType:  事件類型 string 必填
 * callback: 事件執行後的回調 function 必填
 * isnotBubble: 不冒泡 boolean 非必填
 * value of isnotBubble: false(默認值)---冒泡(從裏向外);true---捕獲(從外向裏)
 *
***/

現在對window進行改進, 如下:

window.addEventListener("click", function(){alert("window");}, true); //事件捕獲階段

執行div inner的點擊事件, 彈框順序爲: window->inner;
再執行div outer的點擊事件, 彈框順序爲: window->outer->body->html.
大多數情況下, 很少會用到事件捕獲階段…

如果把div標籤換成button, 會發生什麼情況呢, 如下:

html
<button class="btn1" onclick="btnOuter();">
    <button class="bnt2" onclick="btnMiddle();">
        <a class="btn3" href="javascript:void(0);" onclick="btnInner();">鏈接</a>
    </button>
</button>
css
.btn1, .btn2, .btn3{display:block;}
.btn1{width:100px;border:1px solid red;}
.btn1{width:70px;border:1px solid green;}
.btn1{width:40px;border:1px solid blue;}
js
function btnOuter(){alert("btnOuter");}
function btnMiddle(){alert("btnMiddle");}
function btnInner(){alert("btnInner");}

而佈局完全不是預想中的樣子:

// 瀏覽器渲染後的佈局
<button class="btn1" onclick="btnOuter();"></button>
<button class="bnt2" onclick="btnMiddle();">
        <a class="btn3" href="javascript:void(0);" onclick="btnInner();">鏈接</a>
</button>

如果有人不信的話, 可以自己去試試
而對於a.href=urlbutton.type=submitinput.type=submit 等類似的標籤, 都會在點擊後執行自己標籤的默認事件, 比如a標籤會跳頁面, button會提交表單, 但是在某些時候我們並不希望標籤執行自己的默認事件, 所以再進行改進:
function btnInside改進如下

html
<button class="btn1" onclick="btnOuter();">
    <button class="bnt2" onclick="btnMiddle();">
        <a class="btn3" href="http://www.baidu.com" onclick="btnInner(event);">鏈接</a>
    </button>
</button>
js
function btnInner(e){
        e.preventDefault() || (window.event.returnValue=false); //兼容IE
        alert("btnInner");
    }

此時點擊a btn3, 不會跳頁面.

最後再加一句: IE9(不含)以下竟然不支持addEventListener方法

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章