最近项目中遇到一个实际问题,自己搞了半天没解决,最后在StackOverflow上求助,不到3分钟就得到了解决方案,而且答案意外的很简单——加一个参数。

场景是这样的:有一个表格(事实上这样的表格在这个系统很多),每一行(row)是顾客的信息(名字,订单号,付款金额...),要求点击表格行(tr元素)打开订单详情,点击顾客名字(包裹在一个a元素里,a在td里)时打开顾客信息页面,不打开订单详情。这不简单直接么,jQuery把a元素和tr元素的事件都委托给tbody或者table不就可以了么?

$('tbody').on('click', 'tr', function() {alert('order detail...')}).on('click', 'a', function(e) {e.stopPropagation()alert('contact detail')})   

如果只是在当前单个页面的代码里写这段,没问题。但因为项目很多页面都有这样包含"<a>顾客名字</a>"的地方,于是我干脆在一个每个页面都会引用的js文件中加了一段把这样的a元素(元素类名取为“gotocontact”)的handler委托给document元素的代码,如下(这里假设a元素是叶子元素,即不会有子元素):

// 因为此时还没引入jQuery,所以用了原生方法
document.addEventListener('click', function(e) {var el = e.srcElement || e.target;if (el && el.classList && el.classList.contains('gotocontact')) {e.stopPropagation();alert('going to contact...')}
})

然后在那个页面的代码里把tr元素的handler委托给tbody(id为“list”):

$('#list').on('click', 'tr', function() {alert('order detail...')})

结果这样是有问题的,当点击a元素时两个handler都会触发,不符合预期。

stackoverflow上的答案是在addEventListener参数里添加第三个参数:

document.addEventListener('click', function(e) {var el = e.srcElement || e.target;if (el && el.classList && el.classList.contains('gotocontact')) {e.stopPropagation();alert('going to contact...')}
}, true)
// ^^^^ add third parameter

问题解决。一个参数就解决了?!

知道addEventListener有这个参数选项(MDN),但是根本不知道起什么作用。

然后开始搜索,看到了这篇文章,算是讲得比较通俗易懂的:

W3C标准中DOM事件有3个阶段:capture phase(捕获阶段), target phase(目标阶段), bubble phase(冒泡阶段)。而常用的on<event> 和 addEventListener(event, handler) (注意没有第三个参数)只会作用于后两个阶段。如下图(来自W3C):

把W3C对这张图的说明简单翻译下搬过来:

事件生成后,事件的传播路径(propagation path)先被确定下来,路径是一个有序列表,列表中最后一个元素是目标元素,往前依次是目标元素的父元素、祖先元素,一直到Window对象。接下来事件开始传播(propagate):

1.捕获阶段。事件对象从Window对象开始沿传播路径向下,依次经过各元素传播至目标元素的父元素;

2.目标阶段。事件对象到达目标元素;

3.冒泡阶段。事件对象从目标元素的父元素开始沿传播路径向上,依次经过各元素传播至Window对象。

照着图拿本例来看。没加第三个参数时,两个handler都只在冒泡阶段起作用(jQuery的on方法就是addEventListener不加第三个参数的包装)。当我点击a.gotocontact时,事件对象从Window到达a标签元素这段时间内都没有触发handler。事件对象到达tbody#list时,触发其handler,alert('order detail...'),而此处没有stopPropagation(也不能有,否则事件传播不到document,document的handler就不会触发)。之后到达document,触发handler,alert('going to contact'),而此处的stopPropagation也只是不让事件传到最后的Window对象,事件基本走完了传播路径的一个往返。

加上第三个参数时,addEventListener添加的handler会在捕获阶段起作用。事件传播到document元素时触发handler,这里的stopPropagation停止事件进一步传播。事件刚走了一步就被停止传播,到不了tbody#list,达到预期效果。

参考:

1. Bubbling and capturing

2. UI Events

3. Event | MDN

转载于:https://www.cnblogs.com/Monkey-D-Pixel/p/10070331.html

JavaScript事件的捕获阶段(Capture phase)相关推荐

  1. 深入浅出 Javascript 事件

    转载自:https://www.cnblogs.com/jingwhale/p/4656869.html 深入浅出 Javascript 事件 一.事件流 事件冒泡和事件捕获分别由微软和网景公司提出, ...

  2. javaScript事件(一)事件流

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

  3. JavaScript 事件相关

    一.如何理解JavaScript事件? 个人理解是浏览器或鼠标或键盘触发某个行为而产生的交互.它可能是某种鼠标行为(点击.按下.划过....),也可能是某种键盘操作,亦或是浏览器发生的行为(文档加载完 ...

  4. JavaScript事件流

    JS事件流 1. 什么是事件流 ? 2. 事件流模型 2.1) 事件冒泡 2.2) 事件捕获 3. DOM 事件流 1. 什么是事件流 ? 在学习事件流之前我们先看看什么是事件 ? 事件代表文档或浏览 ...

  5. javascript事件代理

    一,事件介绍 1.事件用来实现js和html之间交互,网页中的每个元素都有一些事件属性可以触发事件处理函数. 2.一个完整的事件包含 (1)事件源 (html元素) (2)事件类型 (click,mo ...

  6. 谈谈JavaScript事件

    何为'事件' 用户在网页中的行为叫做事件 学习事件的目的:希望能自定义的让用户在网页中进行某种行为之后,去执行写好一段代码 语法: 1.事件源.on事件类型=function() {} 2.行内绑定: ...

  7. JavaScript(事件)

    事件定义 用户在网页中的行为叫做事件 学习事件的目的:希望能自定义的让用户在网页中进行某种行为之后,去执行写好一段代码 语法: 事件源:on事件类型 = 函数 行内绑定:<标签 on 事件类型 ...

  8. addeventlistener事件第三个参数_简析JavaScript 事件绑定、事件冒泡、事件捕获和事件执行顺序...

    这篇文章主要介绍了javaScript 事件绑定.事件冒泡.事件捕获和事件执行顺序整理总结的相关资料 (一)事件绑定的几种方式 javascript给DOM绑定事件处理函数总的来说有2种方式:在htm ...

  9. 简析JavaScript 事件绑定、事件冒泡、事件捕获和事件执行顺序

    JavaScript 事件绑定.事件冒泡.事件捕获和事件执行顺序 这篇文章主要介绍了javaScript 事件绑定.事件冒泡.事件捕获和事件执行顺序整理总结的相关资料 (一)事件绑定的几种方式 jav ...

最新文章

  1. gevent queue应用2 队列设置了最大数量限制
  2. ios10申请权限以及弹出允许使用数据框
  3. React 中 keys 的作用是什么?
  4. 教徒计划出品:升级ESXI41-ESXI5
  5. 本地windows主机无法访问虚拟机里主机解决办法
  6. 路由与交换技术(铺垫内容)
  7. Intel CPU 曝两个新漏洞影响所有处理器,设备可遭接管(含视频)
  8. Ubuntu安装最新版nodejs
  9. 微信短视频小程序——视频封面,视频缩略图
  10. 1386 - Cellular Automaton
  11. 关于ROHDESCHWARZ公司电流探头EZ-17系数修正的说明
  12. 什么是firmware?
  13. 依赖、关联、聚合、组合
  14. Linux进程(上)
  15. python字符串算式加减运算(Python字符串运算)
  16. js moment.js 给定时间 获取自然月、周的时间轴
  17. 抛物线断面临界水深莫洛图
  18. AWS上配置Cisco ASAv AnyConnect
  19. 时钟偏差、延迟、不确定度、抖动 (skew,latency,uncertainty,jitter)
  20. 如何用 Lightly 进行 Debug 断点调试?

热门文章

  1. HDFS restful API:关于WebHDFS与HttpFS的区别
  2. 【网址收藏】WSL安装docker(不折腾版)
  3. 【收藏】keepalived nginx服务检测脚本
  4. win10安装docker desktop之后没有ADVANCED选项解决办法
  5. 解决kubesphere node-exporter守护进程pod安装失败的问题
  6. vSphere资源:下载及文档地址
  7. Hadoop hdfs 从指定偏移量读取文件数据代码示例
  8. Python Django 使用cookie实现三天免登录及记住密码功能代码示例
  9. socket编程的三种通信模型,BIO,NIO,AIO
  10. vooc是什么快充协议_5G时代除了网速,快充同样重要!