JavaScript 详说事件机制之冒泡、捕获、传播、委托

本贴最后更新于 1593 天前,其中的信息可能已经渤澥桑田

DOM 事件流(event flow )存在三个阶段:事件捕获阶段、处于目标阶段、事件冒泡阶段。

事件捕获event capturing)*:通俗的理解就是,当鼠标点击或者触发 dom 事件时,浏览器会从根节点开始由外到内*进行事件传播,即点击了子元素,如果父元素通过事件捕获方式注册了对应的事件的话,会先触发父元素绑定的事件。

事件冒泡*(dubbed bubbling)***:**与事件捕获恰恰相反,事件冒泡顺序是由内到外进行事件传播,直到根节点。

无论是事件捕获还是事件冒泡,它们都有一个共同的行为,就是事件传播,它就像一跟引线,只有通过引线才能将绑在引线上的鞭炮(事件监听器)引爆,试想一下,如果引线不导火了,那鞭炮就只有一响了!!!

  

  dom 标准事件流的触发的先后顺序为:先捕获再冒泡,即当触发 dom 事件时,会先进行事件捕获,捕获到事件源之后通过事件传播进行事件冒泡。不同的浏览器对此有着不同的实现,IE10 及以下不支持捕获型事件,所以就少了一个事件捕获阶段,IE11、Chrome 、Firefox、Safari 等浏览器则同时存在。

说到事件冒泡与捕获就不得不提一下两个用于事件绑定的方法 addEventListener、attachEvent。当然还有其它的事件绑定的方式这里不做介绍。 

***  addEventListener(event, listener, useCapture)***  

    *·参数定义:*event---(事件名称,如 click,不带 on),listener---事件监听函数,*useCapture---*是否采用事件捕获进行事件捕捉,

        默认为 false,即采用事件冒泡方式

    addEventListener 在 IE11、Chrome 、Firefox、Safari 等浏览器都得到支持。

  attachEvent(event,listener)  

    ·参数定义:event---(事件名称,如 onclick,带 on),listener---事件监听函数。

    attachEvent 主要用于 IE 浏览器,并且仅在 IE10 及以下才支持,IE11 已经废了这个方法了(微软还是挺识趣的,慢慢向标准靠拢)。

说了一箩筐定义,下面就用上面这两个方法通过栗子来解释一下事件捕获与事件冒泡的具体表现行为差异。

事件冒泡

栗 1:

<html lang="zh-cn"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> <title>js事件机制</title> <style> #parent{ width: 200px; height:200px; text-align: center; line-height: 3; background: green; } #child{ width: 100px; height: 100px; margin: 0 auto; background: orange; } </style> </head> <body> <div id="parent"> 父元素 <div id="child"> 子元素 </div> </div> <script type="text/javascript"> var parent = document.getElementById("parent"); var child = document.getElementById("child"); document.body.addEventListener("click",function(e){ console.log("click-body"); },false); parent.addEventListener("click",function(e){ console.log("click-parent"); },false); child.addEventListener("click",function(e){ console.log("click-child"); },false); </script> </body> </html>

通过"addEventListener"方法,采用事件冒泡方式给 dom 元素注册 click 事件,点击子元素会发生什么呢?如果你对事件冒泡有一定了解的话那你肯定知道上面的代码会输出的顺序,没错,如下图所示:

事件触发顺序是由内到外的,这就是事件冒泡,虽然只点击子元素,但是它的父元素也会触发相应的事件,其实这是合理的,因为子元素在父元素里面,点击子元素也就相当于变相的点击了父元素,这样理解对吧?

这里有同学可能要问了,如果点击子元素不想触发父元素的事件怎么办?肯定可以的,那就是停止事件传播---event.stopPropagation();

修改栗 1 的代码,在子元素的监听函数中加入停止事件传播的操作,栗 2

child.addEventListener("click",function(e){
  console.log("click-child");
   e.stopPropagation();
},false);

在点击子元素的时候就只弹出了子元素那条信息,父元素的事件没有触发,因为事件已经停止传播了,冒泡阶段也就停止了。

事件冒泡差不多就讲述完了,别急,捕获还没说呢!

事件捕获

栗 3,修改栗子 1 中的代码,给 parent 元素注册一个捕获事件,如下

var parent = document.getElementById("parent"); var child = document.getElementById("child"); document.body.addEventListener("click",function(e){ console.log("click-body"); },false); parent.addEventListener("click",function(e){ console.log("click-parent---事件传播"); },false);           //新增事件捕获事件代码 parent.addEventListener("click",function(e){ console.log("click-parent--事件捕获"); },true); child.addEventListener("click",function(e){ console.log("click-child"); },false);

如果你看明白了我前面说的那些,你就知道这个栗子的输出顺序了。

父元素通过事件捕获的方式注册了 click 事件,所以在事件捕获阶段就会触发,然后到了目标阶段,即事件源,之后进行事件传播,parent 同时也用冒泡方式注册了 click 事件,所以这里会触发冒泡事件,最后到根节点。这就是整个事件流程。

上面介绍了事件冒泡、事件捕获、事件传播,下面讲一下如果通过以上三个知识点进行事件****委托

委托在 JQuery 中已经得到了实现,即通过 $(selector).on(event,childSelector,data,function,map)实现委托,一般用于动态生成的元素,当然 JQuery 也是通过原声的 js 去实现的,下面举一个简单的栗子,通过 js 实现通过 parent 元素给 child 元素注册 click 事件

var parent = document.getElementById("parent"); var child = document.getElementById("child"); parent.onclick = function(e){ if(e.target.id == "child"){ console.log("您点击了child元素") } }
虽然没有直接只 child 元素注册 click 事件,可是点击 child 元素时却弹出了提示信息。

  • JavaScript

    JavaScript 一种动态类型、弱类型、基于原型的直译式脚本语言,内置支持类型。它的解释器被称为 JavaScript 引擎,为浏览器的一部分,广泛用于客户端的脚本语言,最早是在 HTML 网页上使用,用来给 HTML 网页增加动态功能。

    730 引用 • 1280 回帖 • 3 关注

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...
zhaozhizheng
没有人会关心你付出过多少努力,撑得累不累,摔得痛不痛,他们只会看你最后站在什么位置,然后羡慕或者鄙夷 北京

推荐标签 标签

  • JVM

    JVM(Java Virtual Machine)Java 虚拟机是一个微型操作系统,有自己的硬件构架体系,还有相应的指令系统。能够识别 Java 独特的 .class 文件(字节码),能够将这些文件中的信息读取出来,使得 Java 程序只需要生成 Java 虚拟机上的字节码后就能在不同操作系统平台上进行运行。

    180 引用 • 120 回帖
  • OpenShift

    红帽提供的 PaaS 云,支持多种编程语言,为开发人员提供了更为灵活的框架、存储选择。

    14 引用 • 20 回帖 • 659 关注
  • RIP

    愿逝者安息!

    8 引用 • 92 回帖 • 397 关注
  • 招聘

    哪里都缺人,哪里都不缺人。

    189 引用 • 1057 回帖 • 5 关注
  • JetBrains

    JetBrains 是一家捷克的软件开发公司,该公司位于捷克的布拉格,并在俄国的圣彼得堡及美国麻州波士顿都设有办公室,该公司最为人所熟知的产品是 Java 编程语言开发撰写时所用的集成开发环境:IntelliJ IDEA

    18 引用 • 54 回帖 • 5 关注
  • DNSPod

    DNSPod 建立于 2006 年 3 月份,是一款免费智能 DNS 产品。 DNSPod 可以为同时有电信、网通、教育网服务器的网站提供智能的解析,让电信用户访问电信的服务器,网通的用户访问网通的服务器,教育网的用户访问教育网的服务器,达到互联互通的效果。

    6 引用 • 26 回帖 • 532 关注
  • Kotlin

    Kotlin 是一种在 Java 虚拟机上运行的静态类型编程语言,由 JetBrains 设计开发并开源。Kotlin 可以编译成 Java 字节码,也可以编译成 JavaScript,方便在没有 JVM 的设备上运行。在 Google I/O 2017 中,Google 宣布 Kotlin 成为 Android 官方开发语言。

    19 引用 • 33 回帖 • 82 关注
  • OpenCV
    15 引用 • 36 回帖 • 2 关注
  • C++

    C++ 是在 C 语言的基础上开发的一种通用编程语言,应用广泛。C++ 支持多种编程范式,面向对象编程、泛型编程和过程化编程。

    107 引用 • 153 回帖 • 3 关注
  • GitBook

    GitBook 使您的团队可以轻松编写和维护高质量的文档。 分享知识,提高团队的工作效率,让用户满意。

    3 引用 • 8 回帖 • 1 关注
  • OneDrive
    2 引用 • 4 关注
  • Elasticsearch

    Elasticsearch 是一个基于 Lucene 的搜索服务器。它提供了一个分布式多用户能力的全文搜索引擎,基于 RESTful 接口。Elasticsearch 是用 Java 开发的,并作为 Apache 许可条款下的开放源码发布,是当前流行的企业级搜索引擎。设计用于云计算中,能够达到实时搜索,稳定,可靠,快速,安装使用方便。

    117 引用 • 99 回帖 • 210 关注
  • 钉钉

    钉钉,专为中国企业打造的免费沟通协同多端平台, 阿里巴巴出品。

    15 引用 • 67 回帖 • 290 关注
  • LeetCode

    LeetCode(力扣)是一个全球极客挚爱的高质量技术成长平台,想要学习和提升专业能力从这里开始,充足技术干货等你来啃,轻松拿下 Dream Offer!

    209 引用 • 72 回帖 • 2 关注
  • Solidity

    Solidity 是一种智能合约高级语言,运行在 [以太坊] 虚拟机(EVM)之上。它的语法接近于 JavaScript,是一种面向对象的语言。

    3 引用 • 18 回帖 • 437 关注
  • CentOS

    CentOS(Community Enterprise Operating System)是 Linux 发行版之一,它是来自于 Red Hat Enterprise Linux 依照开放源代码规定释出的源代码所编译而成。由于出自同样的源代码,因此有些要求高度稳定的服务器以 CentOS 替代商业版的 Red Hat Enterprise Linux 使用。两者的不同在于 CentOS 并不包含封闭源代码软件。

    239 引用 • 224 回帖 • 1 关注
  • API

    应用程序编程接口(Application Programming Interface)是一些预先定义的函数,目的是提供应用程序与开发人员基于某软件或硬件得以访问一组例程的能力,而又无需访问源码,或理解内部工作机制的细节。

    79 引用 • 431 回帖
  • Notion

    Notion - The all-in-one workspace for your notes, tasks, wikis, and databases.

    10 引用 • 77 回帖
  • SOHO

    为成为自由职业者在家办公而努力吧!

    7 引用 • 55 回帖
  • HHKB

    HHKB 是富士通的 Happy Hacking 系列电容键盘。电容键盘即无接点静电电容式键盘(Capacitive Keyboard)。

    5 引用 • 74 回帖 • 503 关注
  • Vim

    Vim 是类 UNIX 系统文本编辑器 Vi 的加强版本,加入了更多特性来帮助编辑源代码。Vim 的部分增强功能包括文件比较(vimdiff)、语法高亮、全面的帮助系统、本地脚本(Vimscript)和便于选择的可视化模式。

    29 引用 • 66 回帖
  • 书籍

    宋真宗赵恒曾经说过:“书中自有黄金屋,书中自有颜如玉。”

    78 引用 • 396 回帖
  • Linux

    Linux 是一套免费使用和自由传播的类 Unix 操作系统,是一个基于 POSIX 和 Unix 的多用户、多任务、支持多线程和多 CPU 的操作系统。它能运行主要的 Unix 工具软件、应用程序和网络协议,并支持 32 位和 64 位硬件。Linux 继承了 Unix 以网络为核心的设计思想,是一个性能稳定的多用户网络操作系统。

    952 引用 • 944 回帖
  • Logseq

    Logseq 是一个隐私优先、开源的知识库工具。

    Logseq is a joyful, open-source outliner that works on top of local plain-text Markdown and Org-mode files. Use it to write, organize and share your thoughts, keep your to-do list, and build your own digital garden.

    7 引用 • 69 回帖
  • Anytype
    3 引用 • 31 回帖 • 12 关注
  • Lute

    Lute 是一款结构化的 Markdown 引擎,支持 Go 和 JavaScript。

    28 引用 • 197 回帖 • 33 关注
  • 机器学习

    机器学习(Machine Learning)是一门多领域交叉学科,涉及概率论、统计学、逼近论、凸分析、算法复杂度理论等多门学科。专门研究计算机怎样模拟或实现人类的学习行为,以获取新的知识或技能,重新组织已有的知识结构使之不断改善自身的性能。

    83 引用 • 37 回帖 • 1 关注