原文地址:https://www.jianshu.com/p/dc1520327022

Js事件分发与DOM事件流

对JavaScript分发事件不熟悉,网上查阅相关资料整理后,记录一下对Javascript事件分发机制相关的知识。
当触发某个事件时会相应生成一个事件对象,而这个事件对象则会根据DOM事件流的方向进传递,看下图:

图为通过DOM事件流在DOM树传递事件的示意

图片来源:http://www.w3.org/TR/DOM-Level-3-Events/#event-flow
事件对象会随着DOM事件流从Window依次向下,最终传递给事件目标。但是在这个过程开始之前,事件对象的传递路径需要先被确定下来。
这个传递路径是一个有序的列表,里面包含了传递到事件目标需要经过的节点。而传递路径反映了文档的树结构。列表里面的最后一项就是事件目标,列表里面先于它的项指向目标的祖先节点,它的上一项指向目标的父节点。
比如上图由Window->Document->html->body->table->tr->td。一旦传递路径被确定了,事件对象就可以经历一个或者多个事件阶段。通常有三个阶段:捕获阶段目标阶段冒泡阶段。某些阶段可能会被跳过,如果浏览器不支持,或者事件对象的传播被停止了。例如,如果把cancelBubble设置为true,冒泡阶段将会被跳过,或者stopPropagation()方法在传递之前就被调用的话,之后所有的阶段都会被跳过。

  • 捕获阶段:事件对象从目标的祖先节点Window开始传播直至目标。
  • 目标阶段:事件对象传递到事件目标。如果事件的type属性表明后面不会进行冒泡操作,那么事件到此就结束了。
  • 冒泡阶段:事件对象以一个相反的方向进行传递,从目标开始,到Window对象结束。
    直接上代码,写了三个嵌套的div:
<!DOCTYPE >
<html>
<head lang="en">
<title></title>
<meta charset="UTF-8">
<style type="text/css">
#parent { width: 300px; height: 300px;padding:10px;background:lightyellow;}
#child { width: 200px; height: 200px; background: lightblue; }
#grandchild { width: 100px; height: 100px; background: lightcoral; }
</style>
</head>
<body>
<div id="parent">
parent
<div id="child">
child
<div id="grandchild">
grandchild
</div>
</div>
</div> <script type="text/javascript">
window.alert = function (msg) {
console.log(msg);
};
var parent= document.getElementById('parent'),
child = document.getElementById('child'),
grandchild = document.getElementById('grandchild'); parent.addEventListener('click', function (e) {
alert('父节点冒泡')
}, false);
parent.addEventListener('click', function (e) {
alert('父节点捕获')
}, true);
child.addEventListener('click', function (e) {
alert('子节点捕获')
}, true);
child.addEventListener('click', function (e) {
alert('子节点冒泡')
}, false);
grandchild.addEventListener('click', function (e) {
alert('孙子节点冒泡')
}, false);
grandchild.addEventListener('click', function (e) {
alert('孙子节点捕获')
}, true); </script>
</body>
</html>

当点击了parent时,依次打印:父节点冒泡,父节点捕获。
当点击了child时,依次打印:父节点捕获,子节点捕获,子节点冒泡,父节点冒泡。
当点击了grandchild时,依次打印:父节点捕获,子节点捕获,孙子节点冒泡,孙子节点捕获,子节点冒泡,父节点冒泡。
由此可以得出来结论,点击了目标节点后,捕获阶段里事件会从外向目标传递;到了目标阶段,捕获和冒泡的执行顺序按照事件被定义的先后顺序执行;最后冒泡阶段,又会由目标向外进行传递。

补充说明事件中stopPropagationstopImmediatePropagation区别:
两都都可以阻止事件的进一步捕获或冒泡,但后者同时可以阻止任何事件处理程序被调用,包括目标阶段的事件。
比如修改上面代码里面子节点的目标事件:

   child.addEventListener('click', function (e) {
alert('子节点捕获')
}, true);
child.addEventListener('click', function (e) {
e.stopPropagation();
// e.stopImmediatePropagation();
alert('子节点捕获2')
}, true);
child.addEventListener('click', function (e) {
alert('子节点冒泡')
}, false);

使用stopPropagation():点击子节点,依次打印:父节点捕获,子节点捕获,子节点捕获2,子节点冒泡。
使用stopImmediatePropagation():点击子节点,依次打印:父节点捕获,子节点捕获,子节点捕获2。
两者都阻止了事件向父节点进行传播,同时使用stopImmediatePropagation()阻止了事件向目标阶段后面的事件的传播。
参考:
https://www.w3.org/TR/DOM-Level-3-Events/#event-flow

如果您在阅读过程中发现有什么问题,欢迎指正。

Js-事件分发与DOM事件流的更多相关文章

  1. [DOM Event Learning] Section 4 事件分发和DOM事件流

    [DOM Event Learning] Section 4 事件分发和DOM事件流 事件分发机制: event dispatch mechanism. 事件流(event flow)描述了事件对象在 ...

  2. Js事件分发与DOM事件流

    这一篇比较透彻:https://www.jianshu.com/p/dc1520327022 点击了目标节点后,捕获阶段里事件会从外向目标传递:到了目标阶段,捕获和冒泡的执行顺序按照事件被定义的先后顺 ...

  3. 自定义控件(视图)2期笔记10:自定义视图之View事件分发机制("瀑布流"的案例)

    1. Touch事件的传递:   图解Touch事件的传递,如下: 当我们点击子View 02内部的Button控件时候,我们就触发了Touch事件. • 这个Touch事件首先传递给了顶级父View ...

  4. js事件捕获,事件冒泡,事件委托以及DOM事件流

    一:DOM事件流: 事件流是从页面接收事件的顺序,DOM2级事件规定事件流包括三个阶段: ①事件捕获阶段:用意在于事件达到目标之前捕获它,在事件捕获阶段事件流模型:document→html→body ...

  5. DOM事件: DOM事件级别、DOM事件流、DOM事件模型、DOM事件捕获过程、自定义事件

    前端面试中只要问到事件,就肯定会有DOM事件:如果回答出来了,就会一直向下延申,其实这些东西都很简单,但我第一次被问到的时候,也是懵的: DOM事件级别: DOM0 element.onclick = ...

  6. cocos2d-x 事件分发机制 ——加速计事件监听

    加速计事件监听机制 在上一篇中介绍了cocos2d-x中的触摸事件机制,这篇来介绍下游戏中也常常常使用到的加速计事件,这些都是游戏中的常常要用到的. 移动设备上一个非常重要的输入源是设备的方向.大多数 ...

  7. cocos2d-x游戏引擎核心(3.x)----事件分发机制之事件从(android,ios,desktop)系统传到cocos2dx的过程浅析

    (一) Android平台下: cocos2dx 版本3.2,先导入一个android工程,然后看下AndroidManifest.xml <application android:label= ...

  8. cocos2d-x 事件分发机制 ——触摸事件监听

    cocos2d-x 3.0 出来已经好久了,也已经用3.0写了几个小游戏,感觉3.0的事件触发机制太赞了,随这里总结一下.也算是对知识的一种回顾和加深理解. 3.0的事件分发机制中.须要也只须要通过创 ...

  9. js和jquery的DOM事件大全

随机推荐

  1. shell脚本:Syntax error: Bad for loop variable错误解决方法(转)

    Linux Mint中写了一个简单的shell脚本,利用for..do..done结构计算1+2+3......+100的值,结果执行"sh -n xxx.sh"检测语法时总是报错 ...

  2. 运维开发笔记整理-URL配置

    运维开发笔记整理-URL配置 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.URL路由 对于高质量的Web应用来说,使用简洁,优雅的URL的路由是一个非常值得重视的细节.Dja ...

  3. C#编译相关知识

    C#代码编译成MSIL代码. 当用户编译一个.NET程序时,编译器将源代码翻译成一组可以有效地转换为本机代码且独立于CPU的指令.当执行这些指令时,实时(JIT)编译器将它们转化为CPU特定的代码.由 ...

  4. python __main__ 里的变量是全局变量 因此在函数里面可以访问到

    __main__ and scoping in python from:https://stackoverflow.com/questions/4775579/main-and-scoping-in- ...

  5. selenium常用的API(二)浏览器窗口设置

    浏览器窗口最大化 # encoding=utf-8 from selenium import webdriver driver = webdriver.Ie(executable_path=" ...

  6. linux文档与目录结构

    Linux文件系统结构 本文转自 https://www.cnblogs.com/pyyu/p/9213237.html Linux目录结构的组织形式和Windows有很大的不同.首先Linux没有“ ...

  7. 更改intellij高亮字体背景颜色

    intellij工具中依次进入file -> settings -> editor -> colors & fonts -> general,在右侧窗口中将result ...

  8. 题解 UVa11388

    题目大意 \(T\) 组数据,每组数据给定两个整数 \(G,L\),输出数对 \(x,y\) 满足 \(GCD(x,y)=G,LCM(x,y)=L\) 且 \(x\) 最小.若无解则输出 \(-1\) ...

  9. zjoj1706: [usaco2007 Nov]relays 奶牛接力跑

    矩阵乘法(快速幂) 为说明方便,这里让\(k\)为点数,\(n\)为路径长度. 先将点都离散化,这样最后的点只有\(2k\)个. 先考虑一种暴力,每次用\(O(k^3)\)的复杂度来暴力更新,设当前长 ...

  10. 为何基于tcp协议的通信比基于udp协议的通信更可靠?

    tcp协议一定是先建好双向链接,发一个数据包要得到确认才算发送完成,没有收到就一直给你重发:udp协议没有链接存在,udp直接丢数据,不管你有没有收到. TCP的可靠保证,是它的三次握手双向机制,这一 ...