资讯专栏INFORMATION COLUMN

你真的理解事件冒泡和事件捕获吗?

amuqiao / 2904人阅读

摘要:事件流是事件冒泡,而的事件流就是事件捕获。所有现代浏览器都支持事件冒泡,并且会将事件一直冒泡到对象。事件捕获的用以在于事件到达预定目标之前捕获它。事件流级事件规定事件流包括三个阶段,事件捕获阶段处于目标阶段和事件冒泡阶段。

最近在复习前端的基础,看到事件这一节的时候,刚好发现了笔记中一道特别好玩并且十分有趣的代码,根据这么一道题目,基本上能够把事件冒泡和事件捕获的盲区给扫空。本文就带你一起来看看这段有趣的代码。

但是,首先我们还是要例行公事,把一些基础的概念过一过,其实也不需要太长的时间。

什么是事件?
JavaScriptHTML之间的交互是通过事件实现的。事件,就是文档或浏览器窗口发生的一些特定的交互瞬间。可以使用监听器(或事件处理程序)来预定事件,以便事件发生时执行相应的代码。通俗的说,这种模型其实就是一个观察者模式。(事件是对象主题,而这一个个的监听器就是一个个观察者)
事件流
事件流描述的就是从页面中接收事件的顺序。而IENetscape提出了完全相反的事件流概念。IE事件流是事件冒泡,而Netscape的事件流就是事件捕获。

打个比喻,如果你把手指放在圆心上(多个同心圆),那么你的手指指向的不是一个圆,而是纸上所有的圆。如果你单击了某个按钮,在单击按钮的同时,也单击了按钮的容器元素,甚至是整个页面。

事件冒泡
IE的事件流叫做事件冒泡。即事件开始时由最具体的元素(文档中嵌套层次最深的那个节点)接收,然后逐级向上传播到较为不具体的节点(文档)。所有现代浏览器都支持事件冒泡,并且会将事件一直冒泡到window对象。

事件捕获
事件捕获的思想是不太具体的节点应该更早的接收到事件,而在最具体的节点应该最后接收到事件。事件捕获的用以在于事件到达预定目标之前捕获它。IE9+、Safari、Chrome、OperaFirefox支持,且从window开始捕获(尽管DOM2级事件规范要求从document)。由于老版本浏览器不支持,所以很少有人使用事件捕获。

DOM事件流
“DOM2级事件”规定事件流包括三个阶段,事件捕获阶段、处于目标阶段和事件冒泡阶段。首先发生的事件捕获,为截获事件提供了机会。然后是实际的目标接收了事件。最后一个阶段是冒泡阶段,可以在这个阶段对事件做出响应。

以上这段话,就是我们DOM事件流的根本了,这段话非常重要,虽然看似简单,但是里面包含着很多小细节,我会在下面例子中全部讲到。

一个十分有趣的例子

现在就开始来讲解这个有趣的例子,先把代码贴上来,大致的结构十分简单。由于segmentfault代码过长时会有滚动条,这里我把它切分,并省略了一些不必要的结点,便于观看。

#a{
    width: 300px;
    height: 300px;
    background: pink;
}
#b{
    width: 200px;
    height: 200px;
    background: blue;
}
#c{
    width: 100px;
    height: 100px;
    background: yellow;
}
var a = document.getElementById("a"),
    b = document.getElementById("b"),
    c = document.getElementById("c");
c.addEventListener("click", function (event) {
    console.log("c1");
    // 注意第三个参数没有传进 false , 因为默认传进来的是 false
    //,代表冒泡阶段调用,个人认为处于目标阶段也会调用的
});
c.addEventListener("click", function (event) {
    console.log("c2");
}, true);
b.addEventListener("click", function (event) {
    console.log("b");
}, true);
a.addEventListener("click", function (event) {
    console.log("a1");
}, true);
a.addEventListener("click", function (event) {
    console.log("a2")
});
a.addEventListener("click", function (event) {
    console.log("a3");
    event.stopImmediatePropagation();
}, true);
a.addEventListener("click", function (event) {
    console.log("a4");
}, true);

整个的html页面就是下面这三个小盒子。

那么现在有三个问题:

如果点击c或者b,输出什么?(答案是a1、a3

stopImmediatePropagation包含了stopPropagation的功能,即阻止事件传播(捕获或冒泡),但同时也阻止该元素上后来绑定的事件处理程序被调用,所以不输出 a4。因为事件捕获被拦截了,自然不会触发 b、c 上的事件,所以不输出 b、c1、c2,冒泡更谈不上了,所以不输出 a2

如果点击a,输出什么?(答案是 a1、a2、a3

不应该是 a1、a3、a2 吗?有同学就会说:“a1、a3可是在捕获阶段被调用的处理程序的,a2 是在冒泡阶段被调用的啊。”这正是要说明的:虽然这三个事件处理程序注册时指定了truefalse,但现在事件流是处于目标阶段,不是冒泡阶段、也不是捕获阶段,事件处理程序被调用的顺序是注册的顺序。不论你指定的是true还是false。换句话来说就是现在点击的是a这个盒子本身,它处于事件流的目标状态,而既非冒泡,又非捕获。(需要注意的是,此时的eventPhase为2,说明事件流处于目标阶段。当点击a的时候,先从document捕获,然后一步步往下找,找到a这个元素的时候,此时的targetcurrentTarget是一致的,所以认定到底了,不需要再捕获了,此时就按顺序执行已经预定的事件处理函数,执行完毕后再继续往上冒泡...)

如果注释掉event.stopImmediatePropagation,点击c,会输出什么?(答案是 a1、a3、a4、b、c1、c2、a2

如果同一个事件处理程序(指针相同,比如用 handler 保存的事件处理程序),用 addEventListenerattachEvent绑定多次,如果第三个参数是相同的话,也只会被调用一次。当然,如果第三个参数一个设置为true,另一个设置为false,那么会被调用两次。
而在这里,都是给监听函数的回调赋予了一个匿名函数,所以其实每个处理函数都会被调用。需要注意的是,如果你还不明白为什么在c上触发的先是c1再是c2的话,那么你就需要在去看看第二个问题所描述的内容了。

以上,就是本文章的内容,文章最后的例子是从网上某个地方看到的,但是具体的出处已经忘记了,如果有同学找到了出处,烦请告知。

参考资料:《JavaScript高级程序设计》

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/90700.html

相关文章

  • 真的理解事件冒泡事件捕获

    摘要:事件流是事件冒泡,而的事件流就是事件捕获。所有现代浏览器都支持事件冒泡,并且会将事件一直冒泡到对象。事件捕获的用以在于事件到达预定目标之前捕获它。事件流级事件规定事件流包括三个阶段,事件捕获阶段处于目标阶段和事件冒泡阶段。 最近在复习前端的基础,看到事件这一节的时候,刚好发现了笔记中一道特别好玩并且十分有趣的代码,根据这么一道题目,基本上能够把事件冒泡和事件捕获的盲区给扫空。本文就带你...

    Cheriselalala 评论0 收藏0
  • 真的理解事件冒泡事件捕获

    摘要:事件流是事件冒泡,而的事件流就是事件捕获。所有现代浏览器都支持事件冒泡,并且会将事件一直冒泡到对象。事件捕获的用以在于事件到达预定目标之前捕获它。事件流级事件规定事件流包括三个阶段,事件捕获阶段处于目标阶段和事件冒泡阶段。 最近在复习前端的基础,看到事件这一节的时候,刚好发现了笔记中一道特别好玩并且十分有趣的代码,根据这么一道题目,基本上能够把事件冒泡和事件捕获的盲区给扫空。本文就带你...

    henry14 评论0 收藏0
  • 真的了解JS的事件

    摘要:基础最后一篇啦,蹭着周六日赶紧写完,其他的都是的或者浏览器能力,高级技巧,使用等杂七杂八的知识点,这里就不一一介绍了,平时编码也用不太到,有兴趣的可以找找相关的书籍前言先说说事件流吧,事件流就是从从开始到目标节点之前的节点进行事件的捕获,在 基础最后一篇啦,蹭着周六日赶紧写完,其他的都是DOM,BOM的api或者浏览器能力,高级技巧,Canvas使用等杂七杂八的知识点,这里就不一一介绍...

    douzifly 评论0 收藏0
  • javascript:深入理解事件

    摘要:所有节点中都包含这两个方法,并且它们都接收个参数要处理的事件名作为事件处理程序的函数和一个布尔值。当这个布尔值为时,表示在捕获阶段调用事件处理程序若果是,表示在冒泡阶段调用事件处理程序。 事件流 定义: 1.事件流描述的是从页面中接收事件的顺序,也可理解为事件在页面中传播的顺序。 2.事件就是用户或浏览器自身执行的某种动作。诸如click(点击)、load(加载)、mouseover(...

    Null 评论0 收藏0
  • 最近遇到的前端面试题(2017.03.08更新版)

    摘要:通过管理组件通信通过驱动视图比较差异进行更新操作作者第七页链接来源知乎著作权归作者所有,转载请联系作者获得授权。达到无刷新的效果。对象的状态不受外界影响。对象代表一个异步操作,有三种状态进行中已完成,又称和已失败。 以下问题解释非本人原创,是根据面试经验整理后觉得更容易理解的解释版本,欢迎补充。 一. 输入url后的加载过程 从输入 URL 到页面加载完成的过程中都发生了什么 计算机...

    linkFly 评论0 收藏0

发表评论

0条评论

amuqiao

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<