网页设计基础第三十四讲:善用监听器和委托:打造高效购物车实践

1,085 阅读4分钟

在JavaScript中,事件处理是实现动态网页交互的核心部分。然而,如何有效地添加和移除事件监听器,如何使用事件对象,以及如何运用事件委托都是开发者需掌握的关键技巧。本篇文章将通过实例讲解这些概念,帮助你更好地管理事件,提高代码的可维护性。

知识回顾

一、事件监听器

事件监听器(Event Listener)是一个函数,用于响应特定事件的发生。当指定事件发生时,浏览器会调用这个函数(处理程序)。使用事件监听器的好处包括:

  1. 多种处理函数:使用 addEventListener() 方法可以为同一个元素的同一事件添加多个处理函数,而使用传统的事件属性(如 onclick)则只允许一个处理函数。
  2. 解除绑定:可以在需要时通过 removeEventListener() 方法解除事件绑定,提高代码的可维护性。
  3. 更好的捕获和冒泡控制addEventListener() 允许开发者指定事件的捕获与冒泡阶段,提供更灵活的事件处理选项。可以通过指定第三个参数来开启捕获,例如 element.addEventListener('click', handler, true)

二、事件委托

事件委托(Event Delegation)是一种优化事件处理的技术,通过将事件监听器绑定到父元素而不是子元素上来提高性能和简化代码。

概念

  • 概念:事件委托的实现原理在于:当一个事件在 DOM 树中冒泡时,它可以被父元素捕获并处理。这样,我们只需在父元素上添加一个监听器,而不是对每个子元素分别添加监听器。

优势

  1. 性能优化:减少了内存占用,特别是在有很多子元素的情况下。如果有大量的子元素,每个元素都添加监听器会占用大量内存,而将一个监听器添加到父元素上可以显著减少内存使用。
  2. 动态元素处理:如果后续通过 JavaScript 动态添加了新的子元素,事件委托仍然有效,因为事件监听器是绑定在父元素上的。这样就不需要为每个新添加的子元素单独添加监听器。
  3. 简化代码:使用事件委托,可以让代码更加简洁,逻辑更清晰。你只需处理一次事件,而不是为每个子元素重复相似的逻辑。

代码示例

以下是一个简单的示例,展示如何使用事件委托:

<ul id="itemList">
    <li>项目1</li>
    <li>项目2</li>
    <li>项目3</li>
</ul>

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

    // 使用事件委托,将单击事件绑定到父元素
    itemList.addEventListener('click', function(event) {
        if (event.target.tagName === 'LI') {
            alert(`你点击了: ${event.target.textContent}`);
        }
    });
</script>

在这个示例中,点击任意 li 项目时,都会触发父级 ul 的事件监听器,显示被点击项目的文本内容。即使后续动态添加了新的 li 项目,也能正常响应点击。

任务描述

我们将创建一个动态的购物车示例,展示如何使用事件监听器以及事件委托来管理列表项(商品)和购物车的交互。

image.png

任务实施

1. HTML结构

首先,我们需要定义购物车的HTML结构,包括商品列表和显示已添加商品的购物车。

<!DOCTYPE html>
<html lang="zh">
<head>
    <meta charset="UTF-8">
    <title>购物车示例</title>
    <style>
        body {
            font-family: Arial, sans-serif;
            text-align: center;
            margin-top: 50px;
        }
        #productList {
            border: 1px solid #ccc;
            padding: 20px;
            margin-bottom: 20px;
        }
        .product {
            padding: 10px;
            margin: 5px;
            border: 1px solid #aaa;
            cursor: pointer;
        }
        #cart {
            border: 1px solid #ccc;
            padding: 10px;
        }
    </style>
</head>
<body>
    <h1>购物车示例</h1>
    <div id="productList">
        <div class="product" data-name="商品1">商品1</div>
        <div class="product" data-name="商品2">商品2</div>
        <div class="product" data-name="商品3">商品3</div>
    </div>
    <h2>购物车</h2>
    <div id="cart">当前购物车为空</div>

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

        // 添加事件处理器
        productList.addEventListener('click', function(event) {
            // 检查点击的目标是否是商品
            if (event.target.classList.contains('product')) {
                const productName = event.target.getAttribute('data-name');
                addToCart(productName);
            }
        });

        // 添加商品到购物车
        function addToCart(productName) {
            // 更新购物车内容
            if (cart.textContent === '当前购物车为空') {
                cart.textContent = `当前购物车: ${productName}`;
            } else {
                cart.textContent += `, ${productName}`;
            }
        }
    </script>
</body>
</html>

2. 事件处理器的添加与移除

  • 添加事件处理器:我们使用addEventListener()来添加事件处理器。相比于传统的onclick属性,addEventListener()可以为同一事件绑定多个处理函数,并不影响其他监听器。这种方式更灵活且可维护性高。
  • 移除事件处理器:通过removeEventListener()可以移除事件处理器。在本示例中我们没有移除处理器,但在需要时,例如动态改变行为时,可以通过保存引用并在适当的时机移除监听器。

3. 事件对象的使用

当事件被触发时,会传递一个事件对象作为参数。该对象包含事件的相关信息。

  • event.target:获取触发事件的目标元素。
  • event.type:获取事件的类型(例如click)。
  • event.preventDefault():阻止默认事件的发生(如阻止链接跳转)。
  • event.stopPropagation():阻止事件向上冒泡。

在我们的示例中,我们使用了event.target来确认哪个商品被点击。

4. 事件委托的概念和实践

事件委托是通过将事件处理器绑定到父元素而不是特定子元素上,以减少内存占用和提升性能。在例子中,我们将点击事件绑定到productList,而不是每个商品。这使得即使新添加商品时,也能自动响应点击。