【20190415】JavaScript-事件流与stopPropagation()、stopImmediatePropagation()的误区解析
这两天仔细看了一下MDN上关于事件流机制和相关方法的文档,发现有个很大的误区。过去我一直以为stopPropagation()就是用来阻止事件冒泡的,甚至很多博客和菜鸟教程上都是这样写的。但实际上文档中对stopPropagation()的解释是:
The
stopPropagation()method of theEventinterface 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 ...
随机推荐
- iOS依赖库管理工具之Carthage
在iOS开发中,我们常会用CocoaPods来进行依赖库的管理.CoaoaPods 是一套整体解决方案,我们在 Podfile 中指定好我们需要的第三方库,然后 CocoaPods 就会进行下载,集成 ...
- 升讯威微信营销系统开发实践:微信接口的 .NET 封装
GitHub:https://github.com/iccb1013/Sheng.WeixinConstruction因为个人精力时间有限,不会再对现有代码进行更新维护,不过微信接口比较稳定,经测试至 ...
- MySQL 的分页查询 SQL 语句
MySQL一般使用 LIMIT 实现分页.基本语句为: SELECT ... FROM ... WHERE ... ORDER BY ... LIMIT ... 在中小数据量的情况下,这样的SQL足够 ...
- [Swift]LeetCode848. 字母移位 | Shifting Letters
We have a string S of lowercase letters, and an integer array shifts. Call the shift of a letter, th ...
- [Swift]LeetCode954. 二倍数对数组 | Array of Doubled Pairs
Given an array of integers A with even length, return true if and only if it is possible to reorder ...
- CentOS 6.5系统上安装SVN服务器
有效地管理源代码的方式是使用工具去帮助我们管理 , SVN(Subversion)就是目前主流的源代码管理工具 , 也称为版本控制工具. 本文主要介绍CentOS6.5上安装SVN服务器,配置SVN服 ...
- spark按某几列删除dataframe重复行
新建一个 dataframe : val conf = new SparkConf().setAppName("TTyb").setMaster("local" ...
- 【Spark篇】---Spark故障解决(troubleshooting)
一.前述 本文总结了常用的Spark的troubleshooting. 二.具体 1.shuffle file cannot find:磁盘小文件找不到. 1) connection timeout ...
- Python内置函数(51)——property
英文文档: class property(fget=None, fset=None, fdel=None, doc=None) Return a property attribute. fget is ...
- Java如何在运行时识别类型信息?
在日常的学习工作当中,有一些知识是我们在读书的时候就能够习得:但有一些知识不是的,需要在实践的时候才能得到真知——这或许就是王阳明提倡的“知行合一”. 在Java中,并不是所有的类型信息都能在编译阶段 ...