先解釋下事件捕獲和冒泡:
捕獲—事件從最上一級標籤開始往下查找,直到捕獲到事件目標(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=url
或 button.type=submit
或 input.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方法