【重读红宝书(JS高程4)】第17章-事件

245 阅读4分钟

这是重读红宝书(JavaScript高级程序设计 第4版)的第5篇文章,本节我们来看看事件:事件流、事件处理程序、事件对象、模拟事件

本节涉及源码见仓库 github.com/adamswan/Re…

1、事件流、事件处理程序/监听器

事件流

DOM2 Events 规范规定事件流分为 3 个阶段:捕获阶段、目标阶段、冒泡阶段

捕获阶段:事件从顶层元素,向下传递,直至目标元素

目标阶段:事件到达目标元素

冒泡阶段:事件从目标元素,向上传递,直至顶层元素

事件处理程序/事件监听器

为响应事件而调用的函数被称为事件处理程序(或事件监听器)

方式1:onxx,它只能添加一个回调

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
    <style>
      .father {
        width: 300px;
        height: 300px;
        background-color: pink;
      }
    </style>
  </head>

  <div class="father">
    <div class="son"></div>
  </div>

  <body>
    <script>
      let father = document.querySelector(".father");

      // 用 onclick 只能加一个回调
      father.onclick = function () {
        console.log("father点击事件1");
      };
    </script>
  </body>
</html>

方式2:addEventListener()

1、它能添加多个回调,多个回调都会被触发,类似观察者模式

2、参数1是事件名、参数2是回调、参数3是布尔值,表示是否 useCapture,默认false,即事件不在捕获阶段触发回调,而是在冒泡阶段触发回调

3、移除事件监听,因为函数地址不同,所以要移除事件时,只能用命令函数或存入变量的匿名函数,否则无法移除事件监听

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
    <style>
      .father {
        width: 300px;
        height: 300px;
        background-color: pink;
      }
    </style>
  </head>

  <div class="father">
    <div class="son"></div>
  </div>

  <body>
    <script>
      let father = document.querySelector(".father");

      // 用 addEventListener 可以加多个回调
      let clickHandler1 = function () {
        console.log("father点击事件2");
      };
      function clickHandler2() {
        console.log("father点击事件3");
      }

      father.addEventListener("click", clickHandler1);
      father.addEventListener("click", clickHandler2);

      // 移除第一个事件监听
      setTimeout(() => {
        father.removeEventListener("click", clickHandler1);
      }, 2000);
    </script>
  </body>
</html>

2、事件对象

事件对象

在 DOM 中发生事件时,所有相关信息都会被收集并存储在一个名为 event 的对象中。这个对象包含了一些基本信息,比如导致事件的元素、发生的事件类型,以及可能与特定事件相关的任何其他数据。

event 上有两个常用方法: preventDefault()、stopPropagation()

preventDefault():

用于阻止特定事件的默认动作,例如取消点击时新开页面

let link = document.getElementById("myLink"); 
link.onclick = function(event) { 
  event.preventDefault(); 
}; 

stopPropagation():

1、用于立即阻止事件在 DOM 结构中传播,事件捕获、事件冒泡都能阻止

2、一般 addEventListener 的第三个参数为 false ,即默认不使用捕获阶段,所以 stopPropagation 通常阻止的是冒泡,但两个阶段它都能阻止

3、阻止捕获、冒泡的意义:如果父子元素都绑定的点击事件回调,stopPropagation 阻止事件传播后,只允许点击事件触发子元素上的回调

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
    <style>
      .father {
        width: 300px;
        height: 300px;
        background-color: pink;
      }
      .son {
        width: 100px;
        height: 100px;
        background-color: skyblue;
      }
    </style>
  </head>

  <div class="father">
    <div class="son"></div>
  </div>

  <body>
    <script>
      let father = document.querySelector(".father");
      let son = document.querySelector(".son");

      father.addEventListener("click", function () {
        console.log("father点击事件");
      });

      son.addEventListener("click", function (e) {
        e.stopPropagation();
        console.log("son点击事件");
      });
    </script>
  </body>
</html>

3、模拟事件

document.createEvent() 用于创建事件对象,主要用于手动创建自定义事件或模拟浏览器原生事件,然后可以将这些事件分发到指定的 DOM 元素上。

自定义事件

创建自定义的事件类型,用于在应用程序中实现自定义的事件驱动机制,增强代码的可扩展性和灵活性

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
  </head>

  <body>
    <div id="myDiv">这是一个 div 元素</div>

    <script>
      // 获取 div 元素
      const div = document.getElementById("myDiv");

      // 为 div 元素添加自定义事件监听器
      div.addEventListener("customEvent", function (event) {
        console.log("自定义事件被触发了,携带的数据是:", event.detail);
      });

      // 创建一个自定义事件
      const customEvent = document.createEvent("CustomEvent");

      // 初始化自定义事件
      customEvent.initCustomEvent("customEvent", true, true, {
        message: "这是自定义事件携带的数据",
      });

      // 分发自定义事件到 div 元素上
      div.dispatchEvent(customEvent);
    </script>
  </body>
</html>

模拟用户交互事件

通过创建并分发事件来模拟用户的操作,例如点击、鼠标移动、键盘输入等,常用于自动化测试中

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
  </head>

  <body>
    <button id="myButton">点击我</button>
    <script>
      // 获取按钮元素
      const button = document.getElementById("myButton");

      // 为按钮添加点击事件监听器
      button.addEventListener("click", function () {
        console.log("按钮被点击了!");
      });

      // 创建一个鼠标事件
      const clickEvent = document.createEvent("MouseEvents");
      // 初始化鼠标事件
      clickEvent.initMouseEvent(
        "click",
        true,
        true,
        window,
        0,
        0,
        0,
        0,
        0,
        false,
        false,
        false,
        false,
        0,
        null
      );
      // 分发事件到按钮上
      button.dispatchEvent(clickEvent);
    </script>
  </body>
</html>