详解JavaScript中的事件流

118 阅读5分钟

前言

JavaScript事件流是指事件在DOM结构中传播和触发的顺序。了解事件流的机制对于编写交互性强的网页或应用程序至关重要。事件流包括三个阶段:捕获阶段、目标阶段和冒泡阶段。在捕获阶段,事件从最外层的元素向目标元素进行传播;在目标阶段,事件到达目标元素并触发;在冒泡阶段,事件从目标元素向外层元素进行传播。了解事件流的顺序和机制有助于开发者更好地理解和处理事件,实现所需的交互效果

事件流的触发:

  1. 捕获阶段: 事件从最外层的祖先元素传递到事件的目标元素,途中经过所有的祖先元素。
  2. 目标阶段: 事件在目标元素上触发。
  3. 冒泡阶段: 事件从目标元素冒泡到最外层的祖先元素,途中经过所有的祖先元素。。

事件流的捕获和冒泡

示例

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>事件流</title>
</head>

<body>
  <div id="parent" style="background-color: black;">
    <button id="child" style="background-color: aqua;">Click</button>
  </div>
  <script>
    const parent = document.getElementById('parent');
    const child = document.getElementById('child');


    child.addEventListener('click', function (event) {
      console.log('Child clicked');
    });

    parent.addEventListener('click', function (event) {
      console.log('Parent clicked ');
    });

  </script>
</body>
</html>

image.png 上述例子展示了事件流的捕获和冒泡阶段。当点击按钮时,事件会在捕获阶段从父元素向下传播,然后在目标阶段触发按钮上的事件处理程序,最后在冒泡阶段从按钮向上传播,因此当我点击click时打印出来的就是Child clickedParent clicked

事件委托

示例

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>事件流</title>
</head>

<body>
  <<ul id="parentList">
    <li>1</li>
    <li>2</li>
    <li>3</li>
    </ul>

    <script>
      const parentList = document.getElementById('parentList');

      parentList.addEventListener('click', function (event) {
        if (event.target.tagName === 'LI') {
          console.log('Clicked on:', event.target.textContent);
        }
      });

    </script>
</body>
</html>

image.png

image.png

上述例子展示了事件委托的实现。通过将事件处理程序添加到父元素,可以在父元素上捕获子元素的事件。当列表项被点击时,控制台会输出相应的消息。

  • 在这个例子中我们有一个包含列表项的父元素。
  • 在父元素上,我们使用addEventListener为点击事件添加一个事件处理程序。
  • 通过检查点击事件的target属性,我们可以确定点击的是哪个子元素。
  • 当列表项被点击时,事件处理程序输出相应的消息。

取消默认行为

示例

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>事件流</title>
</head>

<body>
  <a href="https://www.baidu.com" id="myLink">Example</a>


  <script>
    const myLink = document.getElementById('myLink');

    myLink.addEventListener('click', function (event) {
      event.preventDefault();
      console.log('Link clicked, but default action prevented.');
    });

  </script>
</body>

</html>

image.png

上述例子展示了如何取消链接的默认行为(跳转到链接指定的页面)。当链接被点击时,事件处理程序会阻止默认行为,并在控制台输出一条消息。

  • 我们创建了一个包含链接的元素。
  • 在链接元素上,我们使用addEventListener为点击事件添加一个事件处理程序。
  • 在事件处理程序中,调用event.preventDefault()阻止链接的默认行为,即阻止跳转到链接指定的页面。并在控制台打印信息

阻止事件传播

示例

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>事件流</title>
</head>

<body>
  <div id="parent" style="background-color: black;">
    <button id="child" style="background-color: aqua;">Click</button>
  </div>


  <script>
    const parent = document.getElementById('parent');
    const child = document.getElementById('child');

    parent.addEventListener('click', function (event) {
      console.log('Parent clicked');
    });

    child.addEventListener('click', function (event) {
      console.log('Child clicked');
      event.stopPropagation(); // 阻止事件冒泡
    });


  </script>
</body>

</html>

image.png 与第一个示例不同的是在这个;例子中我们实现了如何在子元素的事件处理程序中阻止事件在冒泡阶段继续传播。当按钮被点击时,子元素的事件处理程序阻止了事件继续传播到父元素。

  • 在父元素上,我们使用addEventListener为点击事件添加一个事件处理程序。
  • 在按钮上,我们添加一个事件处理程序,当按钮被点击时,它输出一条消息并调用event.stopPropagation()来阻止事件在冒泡阶段继续传播。
  • 结果是父元素的事件处理程序不会被触发,只有按钮的事件处理程序会执行。

总结

JavaScript 事件流描述了在网页中,一个元素接收事件的顺序。事件流有两种:冒泡和捕获。事件流的三个阶段分别是捕获阶段、目标阶段和冒泡阶段。

捕获阶段(Capture Phase):

在这个阶段,事件从最外层的祖先元素(文档根元素)向下传播到事件的目标元素。即事件在捕获阶段沿着 DOM 树从父元素传递到子元素。

2. 目标阶段(Target Phase):

事件达到目标元素时,触发事件的目标元素上的事件处理程序。这是事件的目标元素上触发的阶段。

3. 冒泡阶段(Bubble Phase):

在这个阶段,事件从目标元素开始,向上冒泡传递到最外层的祖先元素。即事件在冒泡阶段沿着 DOM 树从子元素传递到父元素。

事件处理程序的注册:

  1. HTML 属性: 直接在 HTML 元素上通过属性注册,例如:<button onclick="handleClick()">Click</button>
  2. DOM 属性: 直接在 JavaScript 代码中为 DOM 元素的属性赋值,例如:element.onclick = handleClick
  3. addEventListener: 使用 addEventListener 方法注册事件处理程序,允许同时注册多个事件处理程序,不会覆盖之前的处理程序,例如:element.addEventListener('click', handleClick)

事件对象:

在事件处理程序中,事件对象(通常命名为 event)包含有关事件的信息,例如触发事件的元素、事件类型、鼠标坐标等。事件对象可以通过事件处理程序的参数传递给处理函数,例如:function handleClick(event) { /* 使用 event 对象 */ }

阻止事件传播:

  • stopPropagation: 在事件处理程序中调用 event.stopPropagation() 可以阻止事件在捕获阶段或冒泡阶段继续传播。

取消默认行为:

  • preventDefault: 在事件处理程序中调用 event.preventDefault() 可以取消事件的默认行为,例如取消表单提交、超链接跳转等默认行为。

事件委托:

事件委托是指将事件处理程序添加到父元素,利用事件的冒泡机制在父元素上捕获子元素触发的事件。这样可以减少事件处理程序的数量,提高性能,并使动态添加的子元素也能被正确处理。