事件的冒泡与捕获

事件

摘自W3school
JavaScript 使我们有能力创建动态页面。事件是可以被 JavaScript 侦测到的行为
网页中的每个元素都可以产生某些可以触发 JavaScript 函数的事件。比方说,我们可以在用户点击某按钮时产生一个 onClick 事件来触发某个函数。事件在 HTML 页面中定义。

事件流

事件流描述的是从页面中接收事件的顺序。不过IE(微软)提出的是冒泡流;网景提出的是捕获流。

事件冒泡

IE提出的事件流叫做事件冒泡,即事件开始时由最具体的元素接收,然后逐级向上传播到较为不具体的节点,自下而上去触发事件,可以形象地比喻为把一颗石头投入水中,泡泡会一直从水底冒出水面。所有现代的浏览器都支持事件冒泡。下面为一个冒泡实例:

<div id="parent">
    parent
    <div id="child">child</div>
</div>

<script>
    var p = document.getElementById('parent');
    var c = document.getElementById('child');
    // 先弹出c后是p
    c.onclick = function(e){alert('c')};
    p.onclick = function(){alert('p')};
</script>
事件捕获

网景公司提出的事件流叫做事件捕获,和事件冒泡相反,即事件会从最外层开始发生,直到最具体的元素,自上而下去触发事件。但是老版本的浏览器是不支持的,所以默认还是冒泡。下面为一个捕获实例:

<div id="parent">
    parent
    <div id="child">child</div>
</div>

<script>
    var p = document.getElementById('parent');
    var c = document.getElementById('child');
    // 先弹出p后是c
    p.addEventListener('click', function(){alert("p")}, true);
    c.addEventListener('click', function(){alert("c")}), true;
</script>
DOM事件流模型

又分为DOM0/DOM2/DOM3级事件。
DOM2级事件规定的事件流包含3个阶段,事件捕获阶段、处于目标阶段、事件冒泡阶段。首先发生的事件捕获为截获事件提供机会,然后是实际的目标接收事件,最后一个阶段是事件冒泡阶段,可以在这个阶段对事件做出响应。事件模型,如下图:
这里写图片描述
由上图可知:
1. 一个完整的JS事件流是从window开始,最后回到window的一个过程
2. 事件流被分为三个阶段(1~5)捕获过程、(5~6)目标过程、(6~10)冒泡过程
示例:

<div id="parent">
    parent
    <div id="child">child</div>
</div>

<script>
    var p = document.getElementById('parent'),
        c = document.getElementById('child');

    /*
     点击子节点依次的触发顺序为:window捕获,父节点捕获,子节点捕获,子节点冒泡,父节点冒泡,window冒泡
     点击父节点依次的触发顺序为:window捕获,父节点捕获,父节点冒泡,window冒泡
     target/currentTarget/eventPhase 都是event里面的属性。
     target是真正发生事件的DOM元素,currentTarget是当前事件发生在哪个DOM元素上,eventPhase表示当前所处阶段。
     eventPhase值为1/2/3,分别表示为:捕获阶段/目标阶段/冒泡阶段
     目标阶段指target === currentTarget或者eventPhase === 2的时候。
     window没有nodeName,所以为undefined
     */
    c.addEventListener('click', function (e) {
        console.log('子节点捕获', e.target.nodeName, e.currentTarget.nodeName, e.eventPhase)
    }, true);
    c.addEventListener('click', function (e) {
        console.log('子节点冒泡', e.target.nodeName, e.currentTarget.nodeName, e.eventPhase)
    }, false);
    p.addEventListener('click', function (e) {
        console.log('父节点捕获', e.target.nodeName, e.currentTarget.nodeName, e.eventPhase)
    }, true);
    p.addEventListener('click', function (e) {
        console.log('父节点冒泡', e.target.nodeName, e.currentTarget.nodeName, e.eventPhase)
    }, false);
    window.addEventListener('click', function (e) {
        console.log('window捕获', e.target.nodeName, e.currentTarget.nodeName, e.eventPhase)
    }, true);
    window.addEventListener('click', function (e) {
        console.log('window冒泡', e.target.nodeName, e.currentTarget.nodeName, e.eventPhase)
    });
</script>

以上执行结果如下图:
这里写图片描述

阻止冒泡

e.stopPropagation()或者e.stopImmediateProgation()或者设置e.cancelBubble = true;均可阻止事件冒泡。
e.cancelBubble = true适用老牌IE浏览器,不过现在主流浏览器也支持,效果同e.stopPropagation();
e.stopPropagation()可阻止事件的向上继续传播,但不会阻止该元素绑定的其他事件的执行;
e.stopImmediateProgation()做了两件事,先是阻止绑定在该元素上的其他事件,再阻止其向上传播。

<div id="parent">
    parent
    <div id="child">child</div>
</div>

<script>
    var p = document.getElementById('parent');
    var c = document.getElementById('child');
    // 第一种情况:先c后p,默认冒泡
    c.onclick = function(e){alert('c')};
    p.onclick = function(){alert('p')};

    // /*
    // 第二种情况:先p后c
    // 原理分析:addEventListener(event, function, boolean)属于DOM2级事件,但有兼容性问题;
    // 对于方法的兼容性查看,可去can i use 即caniuse.com查看。
    // 第三个参数默认不填(即为false)表示冒泡,填写true则表示捕获;
    // 它允许给同一个事件注册多个监听器,下面第五种情况会涉及到。
    // */
    // p.addEventListener('click', function(){alert("p")}, true);
    // c.addEventListener('click', function(){alert("c")}), true;

    // // 第三种情况:只有c,三种方法都可阻止冒泡
    // // c.onclick = function(e){alert('c'); e.cancelBubble = true};
    // // c.onclick = function(e){alert('c'); e.stopImmediatePropagation();};
    // c.onclick = function(e){alert('c'); e.stopPropagation();};
    // p.onclick = function(){alert('p')};

    // /*
    // 第四种情况:先c后p
    // 原因分析:onclick属于DOM0事件,如果同一个元素绑定多个事件,会被后者覆盖
    // */
    // // c.onclick = function(e){alert('c'); e.cancelBubble = true};
    // // c.onclick = function(e){alert('c'); e.stopPropagation();};
    // c.onclick = function(e){alert('c'); e.stopImmediatePropagation();};
    // c.onclick = function(e){alert('c')};
    // p.onclick = function(){alert('p')};

    // // 第五种情况:先c后ccc,绑定的后续事件不能被阻止
    // // c.addEventListener('click', function(e){alert("c"); e.cancelBubble = true;});
    // c.addEventListener('click', function(e){alert("c"); e.stopPropagation();});
    // c.addEventListener('click', function(e){alert("ccc")});
    // p.addEventListener('click', function(){alert("p")});

    // // 第六种情况:只有c,绑定的后续事件被阻止
    // c.addEventListener('click', function(e){alert("c"); e.stopImmediatePropagation();});
    // c.addEventListener('click', function(e){alert("ccc")});
    // p.addEventListener('click', function(){alert("p")});
</script>

阻止默认行为

所谓的默认行为就比如是:点击a标签的时候就跳转;点击表单的提交按钮的时候就会提交表单等。有时候不希望这些事发生,所以就要阻止默认行为了。
1. 使用w3c的e.preventDefault()方法,在IE中使用e.returnValue = false。可阻止默认行为,但不会阻止冒泡,要想阻止冒泡再添加相应的阻止冒泡逻辑;
2. 在原生js中也可使用return false阻止默认行为,但是该方法在 用addEventListener/attachEvent绑定事件的时候,不生效,必须使用方法1;
3. 在jQuery中使用return false即可阻止默认行为又可阻止冒泡。
实现逻辑:

<div id='parent'>
    <a href="http://www.baidu.com" id="a">child</a>     
</div>

<script>
    var p = document.getElementById('parent');
    var a = document.getElementById('a');

    // 正常情况:先弹a,后p,最后跳转
    a.onclick = function (e) {
        alert('弹框关闭后,页面会跳转');
    };

    // // 方法1
    // a.onclick = function (e) {
    //  alert('弹框关闭后,也不会跳转');
    //  if(e.preventDefault){
    //      e.preventDefault();
    //  }else{
    //      window.event.returnValue == false;
    //  }
    //  // e.stopPropagation()
    // };

    // // 方法2 不会跳转
    // a.onclick = function (e) {
    //  alert('弹框关闭后,也不会跳转');
    //  e.stopPropagation();
    //  return false;
    // };
    // // 方法2 仍会跳转
    // a.addEventListener('click', function (e) {
    //  alert('弹框关闭后,也不会跳转了');
    //  // e.preventDefault();
    //  return false;
    // });

    // // 方法3 
    // $('a').on('click', function () {
    //  alert('弹框关闭后,也不会跳转了');
    //  return false;
    // });
    p.onclick = function(){alert('p')};
</script>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值