事件流:阻止事件冒泡、阻止事件捕获preventDefault()、stopPropagation()、return false 之间的区别

本文介绍W3C中事件发生的三个阶段,即捕获、目标和冒泡阶段,阐述冒泡型和捕获型事件的触发顺序。还说明了阻止事件发生的方法,包括阻止冒泡和捕获的不同方式。最后探讨事件函数执行先后顺序,得出捕获阶段先执行,其次目标阶段,最后冒泡阶段,目标阶段先注册先执行的结论。

参考文章:https://www.jb51.net/article/94394.htm


W3C 中定义事件的发生经历三个阶段:

捕获阶段(capturing)、目标阶段(targetin)、冒泡阶段(bubbling)

  • 冒泡型事件:当你使用事件冒泡时,子级元素先触发,父级元素后触发
  • 捕获型事件:当你使用事件捕获时,父级元素先触发,子级元素后触发
  • DOM事件流:同时支持两种事件模型:捕获型事件和冒泡型事件

阻止事件发生的方法:

  • 阻止冒泡:在W3c中,使用 stopPropagation() 方法;在IE下设置 cancelBubble = true
  • 阻止捕获:阻止事件的默认行为,例如 click - <a> 后的跳转。在W3c中,使用 preventDefault() 方法,在 IE 下设置 window.event.returnValue = false

再谈事件函数执行先后顺序:

利用 addEventListener() 在元素上绑定多个事件,且设置不同的事件流。也就是说,先后绑定两个click 事件,一个设置事件冒泡,一个设置事件捕获

我们在outC上触发onclick事件(这个是目标对象),如果我们在outC上同时绑定捕获阶段/冒泡阶段事件处理函数会怎么样呢?

<script>
 
 window.onload = function(){
        var outA = document.getElementById("outA");
        var outB = document.getElementById("outB");
        var outC = document.getElementById("outC");

        // 目标(自身触发事件,是冒泡还是捕获无所谓)
        outC.addEventListener('click',function(){console.log("target2");},true);
        outC.addEventListener('click',function(){alert("target1");},true);

        // 事件冒泡
        outB.addEventListener('click',function(){alert("bubble2");},false);
        outA.addEventListener('click',function(){alert("bubble1");},false);

        // 事件捕获
        outB.addEventListener('click',function(){alert("capture2");},true);
        outA.addEventListener('click',function(){alert("capture1");},true);
  
</script>
 
<body>
 <div id="outA" style="width:400px; height:400px; background:#CDC9C9;position:relative;">
 <div id="outB" style="height:200; background:#0000ff;top:100px;position:relative;">
  <div id="outC" style="height:100px; background:#FFB90F;top:50px;position:relative;"></div> 
 </div>
 </div>
</body>

点击outC的时候,打印顺序是:capture1-->capture2-->target2-->target1-->bubble2-->bubble1。

捕获事件最后才绑定 ,但是最先执行了;然后是目标阶段的事件;最后是冒泡事件。

捕获事件 --> 目标阶段 --> 冒泡事件

由于outC是我们触发事件的目标对象,在outC上注册的事件处理函数,属于DOM事件流中的目标阶段。目标阶段函数的执行顺序:先注册的先执行,后注册的后执行。这就是上面我们说的,在目标对象上绑定的函数是采用捕获,还是采用冒泡,都没有什么关系,因为冒泡和捕获只是对父元素上的函数执行顺序有影响,对自己没有什么影响。如果不信,可以将下面的代码放进去验证。

// 目标(自身触发事件,是冒泡还是捕获无所谓)
    outC.addEventListener('click',function(){console.log("target1");},false);
    outC.addEventListener('click',function(){console.log("target2");},true);
    outC.addEventListener('click',function(){console.log("target3");},true);
    outC.addEventListener('click',function(){console.log("target4");},false);

至此我们可以给出事件函数执行顺序的结论了:捕获阶段的处理函数最先执行,其次是目标阶段的处理函数,最后是冒泡阶段的处理函数。目标阶段的处理函数,先注册的先执行,后注册的后执行。

 

 

 

 

在 Vue2 中使用 `stopPropagation` 阻止事件冒泡时,如果发现未生效,可能是因为以下几个原因及对应的解决方案: 1. **确保正确传递 `event` 对象** 在 Vue 的模板中调用方法时,需要显式地将 `$event` 作为参数传递给方法,否则 `event` 对象不会自动传递到方法中。例如,在模板中应使用 `@click="handle1($event)"`,而不是 `@click="handle1"`,这样在方法中才能获取到 `event` 对象并调用 `stopPropagation` [^3]。 ```html <button @click="handle1($event)">点击1</button> ``` ```javascript methods: { handle1: function(event) { event.stopPropagation(); } } ``` 2. **检查事件绑定层级是否正确** 如果父元素和子元素都绑定了相同的事件类型(如 `click`),需要确保 `stopPropagation` 是在子元素的事件处理中被调用的。如果父元素的事件处理逻辑执行了某些操作,可能会影响子元素的事件冒泡行为 [^3]。 3. **避免使用 `return false`** 在 Vue 中,`return false` 会同时阻止事件冒泡和默认行为,这可能会导致预期之外的结果。如果只需要阻止事件冒泡,应该只调用 `event.stopPropagation()`;如果需要阻止默认行为,则应调用 `event.preventDefault()`。两者分开处理可以更精细地控制事件行为 [^2]。 4. **使用 Vue 的事件修饰符** Vue 提供了事件修饰符来简化常见的 DOM 事件操作,例如 `.stop` 修饰符可以直接阻止事件冒泡,而无需手动调用 `stopPropagation`。使用修饰符可以减少代码量,并提高可读性 [^4]。 ```html <button @click.stop="handle1">点击1</button> ``` 5. **确保没有多个事件监听器冲突** 如果在同一个元素上绑定了多个事件监听器,可能会导致 `stopPropagation` 不按预期工作。检查是否有其他代码也在处理相同的事件,特别是第三方库或全局事件监听器 [^3]。 6. **注意事件捕获冒泡阶段** `stopPropagation` 只能阻止同一阶段的事件传播。如果事件处于捕获阶段,`stopPropagation` 会阻止事件继续向下传播到子元素;如果事件处于冒泡阶段,则会阻止事件向上传播到父元素。确保你了解事件的传播方向,并根据需求选择合适的处理时机 [^1]。 7. **测试环境与浏览器兼容性** 不同浏览器对 DOM 事件的支持可能存在差异,尤其是在旧版浏览器中。确保在主流现代浏览器中进行测试,并查阅相关浏览器的文档以确认其对 `stopPropagation` 的支持情况 [^3]。 ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值