JS事件捕获与冒泡

来源:互联网 发布:网络传播杂志官网 编辑:程序博客网 时间:2024/05/16 01:28

先解释下事件捕获和冒泡:
捕获—事件从最上一级标签开始往下查找,直到捕获到事件目标(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;}
jsfunction 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;}
jsfunction 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>
jsfunction btnInner(e){        e.preventDefault() || (window.event.returnValue=false); //兼容IE        alert("btnInner");    }

此时点击a btn3, 不会跳页面.

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