这两天仔细看了一下MDN上关于事件流机制和相关方法的文档,发现有个很大的误区。过去我一直以为stopPropagation()就是用来阻止事件冒泡的,甚至很多博客和菜鸟教程上都是这样写的。但实际上文档中对stopPropagation()的解释是:

The stopPropagation() method of the Event 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()的误区解析的更多相关文章

  1. JavaScript事件流原理解析

    一.为什么会有这一篇的文章 国庆前几天由于任务比较重,要赶在国庆前把一个进度的任务开发完成,所以也就有点赶,但是却遇到了一个比较奇怪的Bug,导致了任务比预计的延迟了几个小时,对此深表遗憾,所以利用国 ...

  2. 浅析JavaScript事件流——冒泡

    一.什么是事件冒泡流 我们知道事件流指的是从页面中接受事件的顺序. 为了形象理解事件冒泡,可以想象三军主将诸葛亮,在帐内运筹帷幄,眼观六路耳听八方,这时候前方的战事情况就需要靠传令兵来传达,当第一位传 ...

  3. 【原】javascript事件流

    摘要:事件流这个东西是比较重要的,为了让自己更加理解js中的事件流,必须整理整理,梳理一下事件流的各种东西啊.本文大部分内容参考<javascript高级程序设计第三版> 先来一段书里的原 ...

  4. 深入理解javascript事件流

    摘要:事件流这个东西是比较重要的,为了让自己更加理解js中的事件流,必须整理整理,梳理一下事件流的各种东西啊.本文大部分内容参考<javascript高级程序设计第三版> 先来一段书里的原 ...

  5. 深入了解javascript事件流

    摘要:事件流这个东西是比较重要的,为了让自己更加理解js中的事件流,必须整理整理,梳理一下事件流的各种东西啊.本文大部分内容参考<javascript高级程序设计第三版> 先来一段书里的原 ...

  6. javaScript事件流是什么?

    一.事件 事件是文档或者浏览器窗口中发生的,特定的交互瞬间. 事件是用户或浏览器自身执行的某种动作,如click,load和mouseover都是事件的名字. 事件是javaScript和DOM之间交 ...

  7. JavaScript事件流

    什么是JS事件流 早期的IE事件传播方向为由上至下,即从document逐级向下传播到目标元素:而Netscape公司的Netscape Navigator则是朝相反的方向传播, 也就是从目标元素开始 ...

  8. javascript 事件流及应用

    当页面元素触发事件的时候,该元素的容器以及整个页面都会按照特定顺序发生该元素的触发 事件,事件传播的顺序叫做事件流 1.事件流的分类: A.冒泡型事件(所有浏览器都支持)   由明确的事件源到最不确定 ...

  9. javascript事件流机制

    (1)冒泡型事件:事件按照从最特定的事件目标到最不特定的事件目标(document对象)的顺序触发. IE 5.5: div -> body -> document IE 6.0: div ...

随机推荐

  1. Devexpress Ribbon 动态生成菜单

    /// <summary> /// 动态加载菜单 /// </summary> private void GetMenuBind() { //根据登录用户角色菜单动态创建 // ...

  2. 音视频编解码技术(二):AAC 音频编码技术

    一.AAC编码概述 AAC是高级音频编码(Advanced Audio Coding)的缩写,出现于1997年,最初是基于MPEG-2的音频编码技术,目的是取代MP3格式.2000年,MPEG-4标准 ...

  3. CS20SI-tensorflow for research笔记: Lecture2

    本文整理自知乎专栏深度炼丹,转载请征求原作者同意. 本文的全部代码都在原作者GitHub仓库github CS20SI是Stanford大学开设的基于Tensorflow的深度学习研究课程. Tens ...

  4. [Swift]LeetCode933. 最近的请求次数 | Number of Recent Calls

    Write a class RecentCounter to count recent requests. It has only one method: ping(int t), where t r ...

  5. Node.js 多版本安装

    Node.js 多版本安装 Node.js® is a JavaScript runtime built on Chrome's V8 JavaScript engine(Node.js 是一个基于 ...

  6. Python数据写入csv格式文件

    (只是传递,基础知识也是根基) Python读取数据,并存入Excel打开的CSV格式文件内! 这里需要用到bs4,csv,codecs,os模块. 废话不多说,直接写代码!该重要的内容都已经注释了, ...

  7. 专访 | 新浪架构师:0-5年Java工程师的职业规划如何做?

    经历了2018年末的阵痛,大家都积攒着一股暗劲蠢蠢欲动. 3月初即将迎来2019年互联网行业换工作的大潮,技术工程师的升级换位对于一家互联网公司来说无疑是命脉般的存在——技术强则公司强! 如何做一个抢 ...

  8. Java编程——学习大纲

    Java基础 Java基础--JDK的安装和配置 Java基础--Eclipse使用 Java基础--基本概念.数据类型.运算符 Java扩展--整型和浮点型在计算机中的存储格式 Java基础--流程 ...

  9. 面试挂了阿里却拿到网易offer,一个三年Java程序员的面试总结!

    前言 15年毕业到现在有三年多了,最近去面试了阿里集团(菜鸟网络,蚂蚁金服),网易,滴滴,点我达,最终收到点我达,网易offer,蚂蚁金服二面挂掉,菜鸟网络一个月了还在流程中... 最终有幸去了网易. ...

  10. 使用C# (.NET Core) 实现抽象工厂设计模式 (Abstract Pattern)

    本文的概念性内容来自深入浅出设计模式一书. 上一篇文章讲了简单工厂和工厂方法设计模式 http://www.cnblogs.com/cgzl/p/8760250.html, 使用的是披萨店的例子. 文 ...