您的位置:首页 > Web前端 > JavaScript

JS事件捕获与冒泡

2017-06-15 15:53 549 查看
先解释下事件捕获和冒泡:

捕获—事件从最上一级标签开始往下查找,直到捕获到事件目标(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方法
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: