当一个HTML 元素产生一个事件时,该事件会在元素节点与根节点之间按照特定的路径传播,路径所经过的所有节点都会接收到该操作,这个传播过程可称为 DOM 事件流。简单来说,事件流就是从页面中接收事件的顺序,而事件流又分为事件冒泡和事件捕获。

1.事件冒泡

事件冒泡即开始由最具体的元素接受,然后逐级向上传播到较为不具体的节点。它是一个向上传播的过程。

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>Dom</title>
  6. </head>
  7. <body>
  8. <div id="myDiv">点击我</div>
  9. </body>
  10. </html>

如果点击页面中的

元素,那么这个click 事件会按照如下顺序传播:
——> ——> ——> document
click 事件首先在
元素上发生,而这个元素就是我们单击的元素。然后,click事件会沿着 DOM 树向上传播,在每一级节点上都会发生,直至传播到 documnt 对象。
事件冒泡.png

2.事件捕捉

事件捕捉则是与事件冒泡完全相反的过程,它是由最不具体的元素先接收事件,而具体的元素则是最后接收事件。它是一个向下传播的过程。
事件捕捉,单击click会按照如下顺序传播:
document** ——> ——> ——> **


在事件捕捉过程中,documnt对象最先接收到click 事件,然后沿着 DOM 树依次向下,一直传播到事件的具体目标,即
元素。
捕获事假.png

3.DOM事件流

DOM标准规定事件流包括三个阶段: 事件捕捉阶段、处于目标阶段 和 事件冒泡阶段。
DOM事件流.png

  • 事件捕获阶段:实际目标(
    )在捕获阶段不会接收事件。也就是在捕获阶段,事件从document到再到就停止了。上图中为1~3.
  • 处于目标阶段:事件在
    上发生并处理。但是事件处理会被看成是冒泡阶段的一部分。
  • 冒泡阶段:事件又传播回document文档。

    4.事件代理

    事件代理,又称之为事件委托。是JavaScript中常用绑定事件的常用技巧。顾名思义,“事件代理”即是把原本需要绑定在子元素的响应事件委托给父元素,让父元素担当事件监听的职务。事件代理的原理是DOM元素的事件冒泡。

    事件委托的优点

    1.可以大量节省内存占用,减少事件注册,比如在ul上代理所有li的click事件就非常棒

    1. <ul id="list">
    2. <li>item 1</li>
    3. <li>item 2</li>
    4. <li>item 3</li>
    5. ......
    6. <li>item n</li>
    7. </ul>
    8. // ...... 代表中间还有未知数个 li

    2.可以实现当新增子对象时无需再次对其绑定(动态绑定事件)
    HTML代码块

    1. <ul id="myLinks">
    2. <li id="goSomewhere">Go somewhere</li>
    3. <li id="doSomething">Do something</li>
    4. <li id="sayHi">Say hi</li>
    5. </ul>

    原生js做法:

    1. var item1 = document.getElementById("goSomewhere");
    2. var item2 = document.getElementById("doSomething");
    3. var item3 = document.getElementById("sayHi");
    4. item1.onclick = function() {
    5. location.href = "http://www.baidu.com";
    6. };
    7. item2.onclick = function() {
    8. document.title = "事件委托";
    9. };
    10. item3.onclick = function() {
    11. alert("hi");
    12. };

    事件代理:

    1. var item1 = document.getElementById("goSomewhere");
    2. var item2 = document.getElementById("doSomething");
    3. var item3 = document.getElementById("sayHi");
    4. document.addEventListener("click", function (event) {
    5. var target = event.target;
    6. switch (target.id) {
    7. case "doSomething":
    8. document.title = "事件委托";
    9. break;
    10. case "goSomewhere":
    11. location.href = "http://www.baidu.com";
    12. break;
    13. case "sayHi": alert("hi");
    14. break;
    15. }
    16. })

    使用事件委托注意事项

    使用“事件委托”时,并不是说把事件委托给的元素越靠近顶层就越好。事件冒泡的过程也需要耗时,越靠近顶层,事件的”事件传播链”越长,也就越耗时。如果DOM嵌套结构很深,事件冒泡通过大量祖先元素会导致性能损失。