【20190415】JavaScript-事件流与stopPropagation()、stopImmediatePropagation()的误区解析
这两天仔细看了一下MDN上关于事件流机制和相关方法的文档,发现有个很大的误区。过去我一直以为stopPropagation()就是用来阻止事件冒泡的,甚至很多博客和菜鸟教程上都是这样写的。但实际上文档中对stopPropagation()的解释是:
The
stopPropagation()
method of theEvent
interface prevents further propagation of the current event in the capturing and bubbling phases
阻止当前事件在捕获和冒泡阶段的进一步传播,我的理解就是阻止当前事件的继续传播,不仅阻止冒泡,也阻止捕获和目标阶段,只在于你是在哪个阶段调用stopPropagation()的。
事件流过程
一个事件被触发,它的事件流包括三个阶段:捕获、目标、冒泡。捕获阶段的传播路径是:window对象→document→HTML→body→...→target的直接父元素,从最外层最不具体的元素层层传递到最里层具体的元素。目标阶段就是事件目标元素上发生。冒泡阶段与捕获阶段的传播路径正好相反:target→...→body→HTML→document→window,一般会将目标阶段看作冒泡阶段的一部分。
事件的传播路径在事件开始传播之前就已经确定,如果在传播过程中DOM结构发生变化,那么也会按照根据原来的结构而生成的传播路径进行传播。
添加事件监听:addEventListener(eventType, function, useCapture)
useCapture为true,表示该监听器监听捕获阶段的事件,useCapture为false,则监听冒泡阶段的事件。如果是在事件目标元素上添加的事件监听,那么不管useCapture设置为true还是false都能监听到,而且此时的事件阶段eventPhase为2。
简单来说就是为某个元素添加一个事件监听器,当有事件传播到该元素时,如果事件处于捕获阶段,eventPhase=1,那么设置了useCapture为true的监听器就会响应。如果事件传播到该元素时处于冒泡阶段,eventPhase=3,那么设置了useCapture为false的监听器响应。如果事件传播到该元素时处于目标阶段,eventPhase=2,那么不管是设置了true还是false的监听器都能响应。
下面是个例子:
<div class="first">first
<div class="second">
<label>click me
<input type="checkbox" class="target">
</label>
</div>
</div>
<script>
let div1=document.getElementsByClassName('first')[0],
div2=document.getElementsByClassName('second')[0],
target=document.getElementsByClassName('target')[0];
div1.addEventListener('click',(e)=>{
alert('first: '+e.eventPhase+'1');
},true);
div1.addEventListener('click',(e)=>{
alert('first: '+e.eventPhase+'2');
},true);
div1.addEventListener('click',(e)=>{
alert('first: '+e.eventPhase);
},false); div2.addEventListener('click',(e)=>{
alert('second: '+e.eventPhase);
},true);
div2.addEventListener('click',(e)=>{
alert('second: '+e.eventPhase); },false);
target.addEventListener('click',(e)=>{
alert('target: '+e.eventPhase);
},true);
target.addEventListener('click',(e)=>{
alert('target: '+e.eventPhase);
},false);
</script>
点击CheckBox后,依次弹出“first:11”、“first:12”、“second:1”、“target:2”、“target:2”、“second:3”、“first:3”。
stopPropagation()
那么stopPropagation()方法就比较好理解了,如果在某个阶段在事件监听函数里调用了事件的stopPropagation()方法,那么该事件后续的传播过程都会被阻止,不论是捕获还是处于目标或者冒泡。
比如你在捕获阶段监听到事件,并且调用了stopPropagation()方法,那么后续的在子节点上的捕获过程(如果还有的话,如果是在捕获过程的最后一个节点上调用,那么就是直接阻止将要进行的目标过程)、处于目标过程、冒泡过程都会被阻止。如果在处于目标阶段调用,那么后续的冒泡过程被阻止。如果在冒泡过程调用,后续的在其他节点上的冒泡传播被阻止。
这里要注意的是,stopPropagation()是以元素节点间的传播为单位,如果后续的传播过程中事件需要从一个元素节点流转到它的父节点或子节点,那么stopPropagation()将会阻止这样的过程。也就是说在一个元素节点内,它是不起作用的,如果在调用stopPropagation()的元素节点内还存在其他事件监听,并且与调用stopPropagation()的监听器的响应规则是一样的,那么这些其他的监听依然会按顺序响应。
例如在上面的例子中,first有两个捕获阶段的事件监听器,在第一个里调用stopPropagation(),那么第二个监听依然会响应,但是后续的捕获、目标和冒泡过程都被阻止了。因此最终只会弹出first的两个弹窗:“first:11”、“first:12”;
stopImmediatePropagation()
而stopImmediatePropagation()在调用后就直接阻止事件的后续传播过程了,包括同一个元素节点内的过程。如果在调用stopImmediatePropagation()的元素节点上还有其他事件监听,那么在调用stopImmediatePropagation()后,其他事件监听也不会响应。
还是以上面的例子,如果在first的第一个捕获监听器里调用stopImmediatePropagation(),那么最终只会有一个弹窗:“first:11”。
如果在target的捕获监听器里调用stopImmediatePropagation(),弹窗结果是:“first:11”、“first:12”、“second:1”、“target:2”。
preventDefault()
很多人把preventDefault()和阻止冒泡、捕获搞混,实际上preventDefault()和事件传播过程没有关系,它的作用是阻止事件的默认行为,例如a标签在click事件后的默认行为是链接到新的页面,checkbox的click事件默认行为是将修改的选中状态生效。preventDefault()的作用则是阻止这些默认行为,它不会影响事件的传播,而且无论在事件的哪个阶段调用preventDefault(),都能阻止默认行为。
【20190415】JavaScript-事件流与stopPropagation()、stopImmediatePropagation()的误区解析的更多相关文章
- JavaScript事件流原理解析
一.为什么会有这一篇的文章 国庆前几天由于任务比较重,要赶在国庆前把一个进度的任务开发完成,所以也就有点赶,但是却遇到了一个比较奇怪的Bug,导致了任务比预计的延迟了几个小时,对此深表遗憾,所以利用国 ...
- 浅析JavaScript事件流——冒泡
一.什么是事件冒泡流 我们知道事件流指的是从页面中接受事件的顺序. 为了形象理解事件冒泡,可以想象三军主将诸葛亮,在帐内运筹帷幄,眼观六路耳听八方,这时候前方的战事情况就需要靠传令兵来传达,当第一位传 ...
- 【原】javascript事件流
摘要:事件流这个东西是比较重要的,为了让自己更加理解js中的事件流,必须整理整理,梳理一下事件流的各种东西啊.本文大部分内容参考<javascript高级程序设计第三版> 先来一段书里的原 ...
- 深入理解javascript事件流
摘要:事件流这个东西是比较重要的,为了让自己更加理解js中的事件流,必须整理整理,梳理一下事件流的各种东西啊.本文大部分内容参考<javascript高级程序设计第三版> 先来一段书里的原 ...
- 深入了解javascript事件流
摘要:事件流这个东西是比较重要的,为了让自己更加理解js中的事件流,必须整理整理,梳理一下事件流的各种东西啊.本文大部分内容参考<javascript高级程序设计第三版> 先来一段书里的原 ...
- javaScript事件流是什么?
一.事件 事件是文档或者浏览器窗口中发生的,特定的交互瞬间. 事件是用户或浏览器自身执行的某种动作,如click,load和mouseover都是事件的名字. 事件是javaScript和DOM之间交 ...
- JavaScript事件流
什么是JS事件流 早期的IE事件传播方向为由上至下,即从document逐级向下传播到目标元素:而Netscape公司的Netscape Navigator则是朝相反的方向传播, 也就是从目标元素开始 ...
- javascript 事件流及应用
当页面元素触发事件的时候,该元素的容器以及整个页面都会按照特定顺序发生该元素的触发 事件,事件传播的顺序叫做事件流 1.事件流的分类: A.冒泡型事件(所有浏览器都支持) 由明确的事件源到最不确定 ...
- javascript事件流机制
(1)冒泡型事件:事件按照从最特定的事件目标到最不特定的事件目标(document对象)的顺序触发. IE 5.5: div -> body -> document IE 6.0: div ...
随机推荐
- High Availability手册(3): 配置
各种配置在命令行状态下,多用crm进行 Global Cluster Options 这个类型是全局配置,主要包含下面两个: no-quorum-policy quorum的意思是最低法定人数,pac ...
- [Swift]LeetCode146. LRU缓存机制 | LRU Cache
Design and implement a data structure for Least Recently Used (LRU) cache. It should support the fol ...
- [Swift]LeetCode677. 键值映射 | Map Sum Pairs
Implement a MapSum class with insert, and sum methods. For the method insert, you'll be given a pair ...
- CoCos2dx开发:tile地图绘制和Tiled工具的基本使用
1.新建地图: 在Tiled工具里新建文件: 设置地图的地图大小和地图块大小: 新建好的空文件如下: 2.绘制图块: 在Aseprite中建立相应大小(注意:划分的图块为32*32,因此图片大小最好与 ...
- Python 创建递归文件夹
# 创建递归文件夹 def createfiles(filepathname): try: os.makedirs(filepathname) except Exception as err: pri ...
- JVM基础系列第1讲:Java 语言的前世今生
Java 语言是一门存在了 20 多年的语言,其年纪比我自己还大.虽然存在了这么长时间,但 Java 至今都是最大的工业级语言,许多大型互联网公司均采用 Java 来实现其业务系统.大到国际电商巨头阿 ...
- 学生选课系统 c语言
/********************************* *主题:学生选修课程系统设计 * *设计要求: *1.添加功能:程序能够任意添加课程和学生记录,可提供选择界面供用户选择所需要添加 ...
- Zabbix系列之七——添加磁盘IO监测
zabbix给我们提供了一些较常用的监控模板,但现在我们如果想要监控我们磁盘的IO,这时候zabbix并没有给我们提供这么一个模板,所以我们需要自己来创建一个模板来完成磁盘IO的监控. 1. [roo ...
- NIO 简介
上文我们描述了五中IO类型.第一种同步阻塞模型我们我们称之为BIO(Blocking IO), 第三种IO复用模型我们称之为NIO(Nonblocking IO). 上图我们可以很容易的发现 BIO会 ...
- 总结Unity 初学者容易犯的编译与运行时错误
总结Unity 初学者容易犯的编译与运行时错误 1: Untiy 出现编译错误: NewLine In Constant 解决方法: 方法一:如果报错脚本比较少量的话,可能用记事本打开报错的脚 ...