2022-07-11 DOM事件绑定的三种方式以及事件代理

70 阅读3分钟

事件代理

在DOM事件流中,通常分为三个阶段:捕获阶段目标阶段冒泡阶段

image.png

  • 捕获阶段是指事件响应从最外层的window开始,逐渐向内层前进,直到具体事件目标元素。在捕获阶段,不会处理响应元素注册的冒泡事件
  • 目标阶段指触发事件的最底层的元素
  • 冒泡阶段正好与捕获阶段相反,事件的响应是从最底层开始一层一层往外传递到最外层的window

从上图直到,DOM事件流的三个阶段是先捕获阶段然后是目标阶段最后才是冒泡阶段

事件代理也称为事件委托,本质上是利用了浏览器事件冒泡或者事件捕获的机制把一系列子节点元素事件绑定到父节点元素上,节省开销和性能

事件冒泡

IE事件被称为事件冒泡,这是因为事件被定义为从最具体的元素(文档树中最深的节点)开始触发,然后向上传播至没有那么具体的元素(文档),如下:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <title>事件冒泡</title>
    <style>
      #myDiv {
        height: 200px;
        width: 200px;
        background-color: antiquewhite;
      }
    </style>
  </head>
  <body>
    <div id="myDiv">点击</div>
  </body>
</html>

在点击页面上的div元素后,click事件会以如下顺序发生:

  1. <div>
  2. <body>
  3. <html>
  4. document

也就是说,<div>元素,即被点击的元素,最先触发click事件。然后click事件沿DOM树一路向上,在经过的每个节点依次触发,直至到达document对象。如下图:

image.png

所有现代浏览器都支持事件冒泡,只是在实现方式上会有一些变化。IE5.5及早期版本会跳过<html>元素(从<body>直接到document)。现在浏览器中的事件会一直冒泡到window对象

下面给每个元素添加事件,看下冒泡的输出顺序:

<script>
  var divEvent = document.getElementById("myDiv");
  divEvent.addEventListener("click", function () {
    console.log("div");
  });

  document.body.addEventListener("click", function () {
    console.log("body");
  });

  document.addEventListener("click", function () {
    console.log("document");
  });
</script>

image.png

事件捕获

事件捕获的意思是最不具体的节点应该最先收到事件,而最具体的节点应该最后收到事件。事件捕获实际上是为了在事件到达最终目标前拦截事件。如果前面的例子使用事件捕获,则点击<div>元素会以下列顺序触发click事件:

  1. document
  2. <html>
  3. <body>
  4. <div>

在事件捕获中。click事件首先由document元素捕获,然后沿DOM树依次向下传播,直至到达实际的目标元素<div>。如下图:

image.png

事件捕获得到了所有现代浏览器的支持。实际上,所有浏览器都是从window对象开始捕获事件,而DOM2 Events规范规定的是从document开始。由于旧版浏览器不支持,因此实际当中几乎不会使用事件捕获。通常建议使用事件冒泡,特殊情况下可以使用事件捕获

下面给每个元素添加事件,看下输出顺序:

<script>
  var divEvent = document.getElementById("myDiv");
  divEvent.addEventListener(
    "click",
    function () {
      console.log("div");
    },
    true
  );

  document.body.addEventListener(
    "click",
    function () {
      console.log("body");
    },
    true
  );

  document.addEventListener(
    "click",
    function () {
      console.log("document");
    },
    true
  );
</script>

image.png

DOM绑定事件的三种方式

第一种,使用DOM2 Events定义的addEventListener()方法,这个方法暴露在所有DOM节点上,接收3个参数:事件名、事件处理函数和一个布尔值(true表示在捕获阶段调用事件处理程序,false-默认值表示在冒泡阶段调用事件处理程序),使用方式如下:

<script>
  var divEvent = document.getElementById("myDiv");
  divEvent.addEventListener("click", function () {}, false);
</script>

第二种,使用DOM0 Events中传统方式把一个函数赋值给(DOM元素)一个事件处理程序属性。每个元素都有通常小写的事件处理程序属性,比如onclick,使用方式如下:

<script>
  var divEvent = document.getElementById("myDiv");
  divEvent.onclick = function () {
    console.log("div");
  };
</script>

第三种,和第二种比较相似,属于原始版本了,直接在属性上定义方法如下:

<div id="myDiv" onclick="printLog()">点击</div>
<script>
  function printLog() {
    console.log("div");
  }
</script>