网站首页 » 前端开发 » JavaScript » JavaScript 事件冒泡与事件捕获详解
上一篇:
下一篇:

JavaScript 事件冒泡与事件捕获详解

在前端里,说到交互我们就不得不提提 JavaScript 中的事件,而事件又分为很多种,比如:点击事件。但这篇文章的主要内容不是分析有什么事件,而是在另一个角度来了解事件机制。正如标题所说的冒泡以及捕获。

一个事件被触发后,一般会有三个不同的阶段:捕获阶段、目标阶段和冒泡阶段。

捕获阶段:从文档的根节点开始流到目标节点。

目标阶段:当到达目标节点时,进入目标阶段。

冒泡阶段:冒泡正好跟捕获的方向相反,它会沿着捕获的路径往回走,直至根节点。

上面三个就组成了一个完整的事件流。一般地,在默认情况下,事件都会经历以下三个阶段。

说了那么多,那到底事件流的作用是什么?

要想知道事件冒泡与事件捕获对我们来说有什么好处也非常简单。但在一开始我们先来看一个简单的例子:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>事件冒泡与事件捕获详解</title>
</head>
<body>
<div id="d1">
    <div id="d2">
        <div id="d3">
            点我测试
        </div>
    </div>
</div>    
<script>
var iD1 = document.getElementById("d1");
var iD2 = document.getElementById("d2");
var iD3 = document.getElementById("d3");
iD1.addEventListener("click",function(){
    console.log("iD1");
},false)

iD2.addEventListener("click",function(){
    console.log("iD2");
},false)

iD3.addEventListener("click",function(){
    console.log("iD3");
},false)
</script>
</body>
</html>

很简单的一小段代码,分别给三个 div 绑定一个 click 事件。当你点击了 d3 的元素后,你猜猜会输出什么内容?没错控制台里依次输出iD3、iD2、iD1。

如果把addEventListener 方法的最后一个参数 false 改成 true 结果又会怎么样呢?

iD1.addEventListener("click",function(){
    console.log("iD1");
},true)

iD2.addEventListener("click",function(){
    console.log("iD2");
},true)

iD3.addEventListener("click",function(){
    console.log("iD3");
},true)

其它的代码保持不变,此时会在控制台里打印出 iD1、iD2、iD3。

此时估计你脑海里会浮现出至少两个问题。

问题1:为什么会输出三个值(也就是说为什么三个元素的三个事件都执行了)。

问题2:为什么输出的顺序又不一样(true or false 分别是什么意思)?

首先产生问题1和问题2都是因为事件流的机制导致的,这一点估计你应该很清楚。为什么会输出三个值?现在请你回想一下,我们一开始说的事件的三个阶段:捕获 – 目标 – 冒泡。我们不妨把这三个阶段理解成“ 套路 ”。说得接地气点就是“走形式”。不管你是点击事件还是悬浮事件或者是其它事件,这个套路都会跑一遍。然后再根据实践情况有序地执行处于不同阶段的事件所对应的方法。

那么现在问题来了,三个阶段是按什么顺序排的?正如你所看到的就是按:捕获 – 目标 – 冒泡 这样的顺序。也就是说当你按下 iD3 时,JavaScript 引擎就会按着套路跑了一圈,从根节点向着目标节点出发(捕获阶段),当到达目标节点后反弹(目标阶段),按原路径返回到根节点(冒泡阶段)。在这个过程中就会依次触发处于不同阶段的方法。

至于问题2,如果你对 addEventListener() 有了解都应该知道最后一个参数是什么意思。首先它是一个可选的布尔值项,可写可不写,true 代表事件捕获(捕获阶段执行),false 代码事件冒泡(冒泡阶段执行),不写第三个参数则为默认值 false 。

如果不想让事件冒泡,要怎么阻止呢?方法也是非常的简单,因为事件为我们提供了一个方法就下面一行代码:

ev.stopPropagation();

比如上面的例子,我们可以改成像下面这样:

var iD1 = document.getElementById("d1");
var iD2 = document.getElementById("d2");
var iD3 = document.getElementById("d3");
iD1.addEventListener("click", function (ev) {
    console.log("iD1");
}, false)
iD2.addEventListener("click", function (ev) {
    console.log("iD2");
}, false)
iD3.addEventListener("click", function (ev) {
    ev.stopPropagation();
    console.log("iD3");
}, false)

也就是在iD3 的 click 事件里添加 ev.stopPropagation(); ,这样当你点击 iD3 时,事件就不会往上冒泡了,此时控制台里只会打印出 iD3 。

总结:不管怎么样,只有事件一解发就会产生一个 捕获 – 目标 – 冒泡的完整事件流,而你给元素所定义的那些函数就是在相应的阶段被执行。

 

 

  • 微信扫一扫,赏我

  • 支付宝扫一扫,赏我

声明

原创文章,不经本站同意,不得以任何形式转载,如有不便,请多多包涵!

本文永久链接:http://yunkus.com/event-bubble-and-event-capture/

Leave a Reply

Your email address will not be published. Required fields are marked *

评论 END