理解DOM事件流的三个阶段 - Lxxyx的开发笔记 - SegmentFault 思否

本文主要解决两个问题:

  1. 什么是事件流

  2. DOM事件流的三个阶段

起因

在学习前端的大半年来,对DOM事件了解甚少。一般也只是用用onclick来绑定个点击事件。在寒假深入学习JavaScript时,愈发觉得自己对DOM事件了解不够,遂打开我的《JavaScript高级程序设计》,翻到DOM事件那一章,开始第二次学习之旅。
当然,DOM事件所囊括的知识较为庞杂,所以本文专注与自己学习时所碰到的难点,DOM事件流。

流的概念,在现今的JavaScript中随处可见。比如说React中的单向数据流,Node中的流,又或是今天本文所讲的DOM事件流。都是流的一种生动体现。
至于流的具体概念,我们采用下文的解释:

用术语说流是对输入输出设备的抽象。以程序的角度说,流是具有方向的数据。
通通连起来——无处不在的流 淘宝FED--愈之

事件流之事件冒泡与事件捕获

在浏览器发展的过程中,开发团队遇到了一个问题。那就是页面中的哪一部分拥有特定的事件?
可以想象画在一张纸上的一组同心圆,如果你把手指放在圆心上,那么你的手指指向的其实不是一个圆,而是纸上所有的圆。放到实际页面中就是,你点击一个按钮,事实上你还同时点击了按钮所有的父元素。
开发团队的问题就在于,当点击按钮时,是按钮最外层的父元素先收到事件并执行,还是具体元素先收到事件并执行?所以这儿引入了事件流的概念。

事件流所描述的就是从页面中接受事件的顺序。

因为有两种观点,所以事件流也有两种,分别是事件冒泡和事件捕获。现行的主流是事件冒泡。

事件冒泡

事件冒泡即事件开始时,由最具体的元素接收(也就是事件发生所在的节点),然后逐级传播到较为不具体的节点。
举个栗子,就很容易明白了。

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Event Bubbling</title>
</head>
<body><button id="clickMe">Click Me</button>
</body>
</html>

然后,我们给button和它的父元素,加入点击事件。

var button = document.getElementById('clickMe');button.onclick = function() {console.log('1. You click Button');
};
document.body.onclick = function() {console.log('2. You click body');
};
document.onclick = function() {console.log('3. You click document');
};
window.onclick = function() {console.log('4. You click window');
};

效果如图所示:

在代码所示的页面中,如果点击了button,那么这个点击事件会按如下的顺序传播(Chrome浏览器):

  1. button

  2. body

  3. document

  4. window

也就是说,click事件首先在<button>元素上发生,然后逐级向上传播。这就是事件冒泡。

事件捕获

事件捕获的概念,与事件冒泡正好相反。它认为当某个事件发生时,父元素应该更早接收到事件,具体元素则最后接收到事件。比如说刚才的demo,如果是事件捕获的话,事件发生顺序会是这样的:

  1. window

  2. document

  3. body

  4. button


当然,由于时代更迭,事件冒泡方式更胜一筹。所以放心的使用事件冒泡,有特殊需要再使用事件捕获即可。

DOM事件流

DOM事件流包括三个阶段。

  1. 事件捕获阶段

  2. 处于目标阶段

  3. 事件冒泡阶段

如图所示(图片源于网络,若侵权请告知):

1. 事件捕获阶段

也就是说,当事件发生时,首先发生的是事件捕获,为父元素截获事件提供了机会。
例如,我把上面的Demo中,window点击事件更改为使用事件捕获模式。(addEventListener最后一个参数,为true则代表使用事件捕获模式,false则表示使用事件冒泡模式。不理解的可以去学习一下addEventListener函数的使用)

window.addEventListener('click', function() {console.log('4. You click window');
}, true);

此时,点击button的效果是这样的。
 

可以看到,点击事件先被父元素截获了,且该函数只在事件捕获阶段起作用。

处于目标与事件冒泡阶段

事件到了具体元素时,在具体元素上发生,并且被看成冒泡阶段的一部分。
随后,冒泡阶段发生,事件开始冒泡。

阻止事件冒泡

事件冒泡过程,是可以被阻止的。防止事件冒泡而带来不必要的错误和困扰。
这个方法就是:stopPropagation()
我们对button的click事件做一些改造。

button.addEventListener('click', function(event) {// event为事件对象console.log('1. You click Button');event.stopPropagation();console.log('Stop Propagation!');
}, false);

点击后,效果如下图:

不难看出,事件在到达具体元素后,停止了冒泡。但不影响父元素的事件捕获。

总结与感想

事件流:描述的就是从页面中接受事件的顺序。分有事件冒泡与事件捕获两种。
DOM事件流的三个阶段:

  1. 事件捕获阶段

  2. 处于目标阶段

  3. 事件冒泡阶段

在学习DOM事件的过程中,了解了DOM事件的三个阶段,也知道事件冒泡是干啥用的,又如何阻止。配合前期所学的二叉树的相关知识,受益匪浅。

前端路漫漫,且行且歌~
最后附上本人博客地址和原文链接,希望能与各位多多交流。

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/248984.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

支付宝APP支付 统一下单 php服务端 tp5

/*支付宝第三方支付 * *生成APP支付订单信息 * param number  uid 用户id * param string   token 用户token * param number  oid 订单id * param string   title 标题 * param string    body …

python第十九天(random、json、pickle、hashlib、hmac、shutil、shevle模块)

今日内容&#xff1a; 1. random 模块 2. json模块 3. pickle 模块 4.hashlib 模块 5. hmac 模块 6. shutil 模块 7. shelve 模块 1. random 模块&#xff1a; random 模块 获取随机值import randomfor i in range(10): print(random.random()) # random.random() 随机获取…

NodeJS入门04-Express路由和中间件 - 小之 - 博客园

nodeJS入门04-Express路由和中间件 Express框架是后台的Node框架&#xff0c;在后台的受欢迎的程度&#xff0c;和jQuery一样&#xff0c;就是企业的事实上的标准。 路由 路由是指如何定义应用的端点&#xff08;URIs&#xff09;以及如何响应客户端的请求。 路由是由一个 …

jmeter(四十五)常用Beanshell脚本

整理了一批jmeter常用的beanshell脚本供大家参考&#xff01; 时间戳 import java.text.SimpleDateFormat; import java.util.Calendar; import java.util.Date; try{ Date date new Date(); //获取当前时间 SimpleDateFormat sf new SimpleDateFormat("yyyy-MM-dd HH:mm…

Critical error detected c0000374

我发现出现上述错误是 free 两次内存 float* ddnew float[2];delete[] dd;delete[] dd;转载于:https://www.cnblogs.com/hook-gou/p/9994662.html

nodejs开发 过程中express路由与中间件的理解 - pyj063 - 博客园

nodejs开发 过程中express路由与中间件的理解 nodejs开发 express路由与中间件 路由 通常HTTP URL的格式是这样的&#xff1a; http://host[:port][path] http表示协议。 host表示主机。 port为端口&#xff0c;可选字段&#xff0c;不提供时默认为80。 path指定请求资源的…

错误MSB4018 “ResolvePackageAssets”任务意外失败的解决方法

昨天系统奔溃了&#xff0c;重装系统后发现&#xff0c;之前写的.netcore项目打开后重新生成报错&#xff0c;错误如下严重性 代码 说明 项目 文件 行 禁止显示状态 错误 MSB4018 “ResolvePackageAssets”任务意外失败。 NuGet.Packaging.Core.Packag…

(五)Unity插件生成

1&#xff09;新建空的AndroidStudio工程&#xff0c;但是新建过程时最小SDK版本要与unity一致&#xff0c;如下图所示&#xff0c;本次操作均为api16 2&#xff09;创建Library&#xff0c;如下图所示&#xff0c;新建module&#xff0c;然后选择Android Library。 新建模块为…

centeros7安装mysql - 风中追风_lonely - 博客园

转载自&#xff1a;https://www.linuxidc.com/Linux/2016-09/135288.htm 安装之前先安装基本环境&#xff1a;yum install -y perl perl-Module-Build net-tools autoconf libaio numactl-libs 1、配置YUM源 在MySQL官网中下载YUM源rpm安装包&#xff1a;http://dev.mysql.c…

失物招领平台6

昨天做了什么&#xff1a;学习了复选框、列表视图、网络视图&#xff0c;集体讨论了登录页面的构思 今天准备做什么&#xff1a;继续学习Android stdio&#xff0c;改善登录页面 遇到的问题&#xff1a;时间远远不够。转载于:https://www.cnblogs.com/sljslj/p/11056074.html

前后端交互json字符串

//将需要的参数转成json字符串&#xff0c;然后用utf-8编码 var obj encodeURIComponent(JSON.stringify(this.categories),"utf-8") //后台将前台的json字符串按照utf-8的格式解码&#xff0c;然后进行转换 RequestMapping(value "/updateMaterialDemoInfo.d…

CSS布局解决方案(终结版)

前端布局非常重要的一环就是页面框架的搭建&#xff0c;也是最基础的一环。在页面框架的搭建之中&#xff0c;又有居中布局、多列布局以及全局布局&#xff0c;今天我们就来总结总结前端干货中的CSS布局。 居中布局 水平居中 1&#xff09;使用inline-blocktext-align &…

个人作业7 第一阶段SCRUM冲刺(七)

了解了一下云服务器&#xff0c;下载了阿里云。 然而搞了半天还是没应用上这个云服务器..转载于:https://www.cnblogs.com/jbwen/p/11071733.html

Dcloud HTML5 监听蓝牙设备 调用 原生安卓实现 - aspirant - 博客园

最近一直搞Dcloud &#xff0c;这是HTML5版本的开发&#xff0c;打包时候&#xff0c;可以打包成 apk 和ipa 分别运行在安卓和ios 机器上面&#xff0c; 但是这里面的资料很少&#xff0c;遇到问题&#xff0c;之后只能自己钻研总结&#xff0c; 现在有这么一个需求&#xff…

NOIP2018游记

NOIP 2018 游记 又是一年 \(NOIP\) 呢...第二次参加了,希望这一次能不再擦线吧...毕竟我真的很想去 \(WC\) ,也很想去省选. 最后悔的事就是在初三了,恰逢直升,大好年华,停课学 \(OI\) ,但我竟然在某两位 \(dalao\) 带领下搓了一年 炉石 \(\& \: SC2\) &#xff1f;&#xf…

四叶草社交平台——十天冲刺(5)

今天没能安排好各种的任务&#xff0c;姑且拍了张照片就散了。 我的任务就是把登录功能完成&#xff0c;先让其他人把资源载入问题解决了&#xff0c;然后我再看看动态如何发送。 转载于:https://www.cnblogs.com/limitCM/p/10925161.html

Django forms组件

校验字段 模板文件 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>Title</title> </head> <body> <form action"" method"post"><p>用户名: <…

为什么要用TypeScript - 肉猪 - 博客园

为什么要用TypeScript 以下是本人的一点拙见&#xff0c;欢迎指正。 TypeScript的设计目的应该是解决JavaScript的“痛点”&#xff1a;弱类型和没有命名空间&#xff0c;导致很难模块化&#xff0c;不适合开发大型程序。另外它还提供了一些语法糖来帮助大家更方便地实践面向…

java继承上机作业

实现如下类之间的继承关系&#xff0c;并编写Music类来测试这些类。 1 package su;2 3 class Instrument{4 public void play() {5 System.out.println("弹奏乐器");6 }7 8 public void play2() {9 // TODO 自动生成的方法存根 10 …

自定义标签的作用

1&#xff09;控制标签体内容是否输出 2&#xff09;控制标签余下内容是否输出 3&#xff09;控制重复输出标签体内容 4&#xff09;改变标签体内容 5&#xff09;带属性的标签 package com.loaderman.demo.a_tag;import java.io.IOException; import java.io.StringWriter;imp…