JS中事件处理机制(秒懂事件委托、事件捕获和事件冒泡)

24 篇文章 0 订阅
1 篇文章 0 订阅

目录

一、概念

事件委托(Event Delegation):

事件捕获(Event Capturing):

事件冒泡(Event Bubbling):

 二、好处

事件委托的好处:

事件捕获的好处:

事件冒泡的好处:

三、工作原理

事件委托(Event Delegation):

事件捕获(Event Capturing):

事件冒泡(Event Bubbling):

四、代码实例

1.简单代码实例(事件监听)

2.复杂代码实例(简单的待办事项列表)

 五、应用场景


一、概念

  当用户在网页上进行交互时,例如点击按钮、输入文本或者滚动页面,这些操作都会触发事件。在 JavaScript 中,我们可以通过事件处理程序来捕获和处理这些事件。事件委托、事件捕获和事件冒泡是与事件处理相关的重要概念。

  1. 事件委托(Event Delegation)

    • 事件委托是一种利用事件冒泡机制的技术,它允许我们将事件处理程序绑定到父元素上,而不是在每个子元素上都绑定事件处理程序。
    • 当一个事件发生在子元素上时,它会冒泡到父元素,然后由父元素上的事件处理程序来处理。这样做的好处是减少了事件处理程序的数量,尤其适用于动态生成的内容。
    • 举例来说,如果有一个列表,我们希望对列表中的每个项都执行相同的操作,那么我们可以将点击事件处理程序绑定到整个列表的父元素上,而不是在每个列表项上都绑定。
  2. 事件捕获(Event Capturing)

    • 事件捕获是事件处理的第一个阶段,在事件到达目标元素之前发生。
    • 当一个事件发生时,它会从文档树的根节点开始向下传播至目标元素。在这个过程中,如果某个元素在捕获阶段上绑定了事件处理程序,那么这些事件处理程序会按照捕获的顺序被依次执行。
    • 事件捕获阶段很少被使用,因为它相对不常见,而且大多数情况下我们更关心事件的冒泡阶段。
  3. 事件冒泡(Event Bubbling)

    • 事件冒泡是事件处理的第二个阶段,在事件到达目标元素之后发生。
    • 当一个事件发生时,它会从目标元素开始向上冒泡至文档树的根节点。在这个过程中,如果某个元素或者它的祖先元素上绑定了事件处理程序,那么这些事件处理程序会按照冒泡的顺序被依次执行。
    • 事件冒泡是 JavaScript 中最常用的事件处理机制,因为它使得我们可以在较高级别的元素上捕获事件,并且更容易管理事件处理程序。

综上所述,事件委托利用了事件冒泡的特性来简化事件处理程序的管理和提高性能,而事件捕获相对不常用。在实际开发中,我们通常更关心事件冒泡,因为它能够更好地满足我们的需求。 

 二、好处

  1. 事件委托的好处

    • 减少事件处理程序的数量:通过将事件处理程序绑定到父元素上,而不是在每个子元素上都绑定,可以减少事件处理程序的数量。特别是在处理大量动态生成的内容时,这可以显著提高性能和降低内存消耗。
    • 更好的性能:减少了事件处理程序的数量通常意味着更好的性能,因为减少了浏览器需要管理和执行的代码量。
    • 简化代码逻辑:通过将事件处理程序绑定到父元素上,可以更轻松地管理和维护代码,减少重复和冗余的代码。
  2. 事件捕获的好处

    • 更精确的控制:虽然事件捕获阶段相对较少使用,但在某些情况下,它可以提供更精确的事件处理,尤其是在需要在事件到达目标元素之前拦截并处理事件时。
    • 改变默认行为:通过在捕获阶段处理事件,可以在事件到达目标元素之前阻止默认行为,或者在不到达目标元素时取消事件传播。
  3. 事件冒泡的好处

    • 更灵活的事件处理:事件冒泡是 JavaScript 中最常用的事件处理机制,它使得我们可以在更高级别的元素上捕获事件,并且更容易地管理事件处理程序。
    • 易于理解和维护:事件冒泡符合人们对于事件传播的直觉理解,从目标元素开始,事件像气泡一样冒泡至根节点。这使得代码更易于理解和维护。
    • 动态绑定事件处理程序:通过利用事件冒泡,可以动态地添加或删除事件处理程序,而不需要重新绑定每个子元素的事件处理程序。

三、工作原理

  1. 事件委托(Event Delegation)

      工作原理:事件委托利用了事件冒泡的特性。当事件在 DOM 树中的某个元素上触发时,该事件会沿着DOM树向上传播,直至根节点。在这个过程中,父元素可以捕获到子元素触发的事件。因此,当我们将事件处理程序绑定到父元素上时,父元素可以代理处理子元素上的事件,这就是事件委托的原理。
  2. 事件捕获(Event Capturing)

      工作原理:事件捕获阶段是事件处理的第一个阶段。当事件在 DOM 树中某个元素上触发时,事件首先会从根节点(document)开始,沿着DOM树向下传播直至达到目标元素。在这个传播过程中,每个祖先元素都有机会捕获到这个事件。因此,如果在某个祖先元素上绑定了事件处理程序,并且该事件处理程序使用了事件捕获阶段,那么该事件处理程序会在目标元素的事件处理程序之前执行。
  3. 事件冒泡(Event Bubbling)

      工作原理:事件冒泡是事件处理的第二个阶段。当事件在目标元素上触发后,它会从目标元素开始,沿着DOM树向上传播至根节点。在这个传播过程中,每个祖先元素都有机会捕获到这个事件。因此,如果在某个祖先元素上绑定了事件处理程序,并且该事件处理程序使用了事件冒泡阶段,那么该事件处理程序会在目标元素的事件处理程序之后执行。

四、代码实例

1.简单代码实例(事件监听)

HTML 结构如下: 

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Event Handling Example</title>
</head>
<body>
  <ul id="parentList">
    <li>Item 1</li>
    <li>Item 2</li>
    <li>Item 3</li>
    <li>Item 4</li>
    <li>Item 5</li>
  </ul>
</body>
</html>

现在我们来使用 JavaScript 来实现事件委托、事件捕获和事件冒泡: 

document.addEventListener('DOMContentLoaded', function() {
  var parentList = document.getElementById('parentList');

  // 事件委托
  parentList.addEventListener('click', function(event) {
    if (event.target.tagName === 'LI') {
      console.log('You clicked on: ', event.target.textContent);
    }
  });

  // 事件捕获
  parentList.addEventListener('click', function(event) {
    console.log('Capturing phase: ', event.target.textContent);
  }, true);

  // 事件冒泡
  parentList.addEventListener('click', function(event) {
    console.log('Bubbling phase: ', event.target.textContent);
  });
});

我们首先获取了父元素 parentList,然后分别为它添加了事件监听器。其中:

  • 事件委托示例:我们将点击事件绑定在父元素 parentList 上,但是在事件处理程序中判断是否点击的是 li 元素。这样,无论点击的是哪个 li 元素,都会被委托到父元素上进行处理。

  • 事件捕获示例:通过在添加事件监听器时传入 true 参数,我们开启了事件捕获阶段的监听。在事件捕获阶段,会从根节点开始,逐级向下直到目标元素,所以我们在事件捕获阶段输出了点击的目标元素的文本内容。

  • 事件冒泡示例:事件冒泡是默认的事件处理机制,所以我们在不传入参数或传入 false 参数时即为事件冒泡。在事件冒泡阶段,事件会从目标元素开始,逐级向上直到根节点,所以我们在事件冒泡阶段输出了点击的目标元素的文本内容。

你可以尝试在浏览器中运行这段代码,并点击 li 元素来查看控制台输出。

2.复杂代码实例(简单的待办事项列表)

HTML 结构如下: 

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Event Handling Example</title>
<style>
  .item {
    cursor: pointer;
  }
</style>
</head>
<body>
  <div id="app">
    <input type="text" id="addItemInput" placeholder="Enter item...">
    <button id="addItemBtn">Add Item</button>
    <ul id="itemList">
      <li class="item">Item 1 <button class="deleteBtn">Delete</button></li>
      <li class="item">Item 2 <button class="deleteBtn">Delete</button></li>
      <li class="item">Item 3 <button class="deleteBtn">Delete</button></li>
    </ul>
  </div>
</body>
</html>

JavaScript 来实现: 

document.addEventListener('DOMContentLoaded', function() {
  var itemList = document.getElementById('itemList');
  var addItemInput = document.getElementById('addItemInput');
  var addItemBtn = document.getElementById('addItemBtn');

  // 添加项目
  addItemBtn.addEventListener('click', function() {
    var newItemText = addItemInput.value.trim();
    if (newItemText !== '') {
      addItem(newItemText);
      addItemInput.value = '';
    }
  });

  // 删除项目
  itemList.addEventListener('click', function(event) {
    var target = event.target;
    if (target.classList.contains('deleteBtn')) {
      deleteItem(target.parentElement);
    }
  });

  // 切换项目状态
  itemList.addEventListener('click', function(event) {
    var target = event.target;
    if (target.classList.contains('item')) {
      toggleItemStatus(target);
    }
  });

  // 添加项目函数
  function addItem(text) {
    var newItem = document.createElement('li');
    newItem.textContent = text;
    newItem.classList.add('item');
    newItem.innerHTML += ' <button class="deleteBtn">Delete</button>';
    itemList.appendChild(newItem);
  }

  // 删除项目函数
  function deleteItem(item) {
    item.remove();
  }

  // 切换项目状态函数
  function toggleItemStatus(item) {
    item.classList.toggle('completed');
  }
});

   我们创建了一个简单的待办事项列表。用户可以输入新项目的名称,然后点击 "Add Item" 按钮来添加项目。每个项目都有一个删除按钮,点击该按钮可以删除项目。此外,用户还可以点击项目本身来切换项目的完成状态(通过添加或删除 completed 类来实现)。我们使用了事件委托来处理添加和删除按钮的点击事件,以及处理列表项的点击事件。 

 五、应用场景

  1. 动态添加元素:当页面中的元素是动态生成的(例如通过 JavaScript 创建或添加),事件委托非常有用。你可以将事件绑定到父元素上,而不是每个动态生成的子元素上。

  2. 列表或表格中的项目操作:例如,在待办事项列表中,可以使用事件委托来处理项目的添加、删除、完成等操作。

  3. 表单验证:当你有一个大型的表单,并且需要对输入的内容进行验证时,可以使用事件委托来处理表单的提交和验证。你可以将提交事件绑定到表单的父元素上,然后根据需要检查表单中的输入字段。

  4. 模态框和弹出窗口:在使用模态框或弹出窗口时,通常希望在模态框外部的区域点击以关闭模态框。这可以通过事件委托在模态框的父元素上捕获点击事件来实现。

  5. 菜单和导航:在网站的导航菜单或侧边栏中,可以使用事件委托来处理菜单项的点击事件,以及展开或折叠子菜单。

  6. 事件代理:在特定情况下,事件委托可以用作事件代理,即将一个对象上的事件委托到另一个对象上,使得第一个对象可以监听和响应第二个对象上的事件。

  7. 性能优化:使用事件委托可以减少事件处理程序的数量,从而提高性能,特别是在处理大量元素时。

  8. 处理动画和过渡结束事件:当你需要在动画或过渡结束时执行操作时,可以使用事件委托来捕获这些事件。

  • 23
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值