Event delegation in the frontend

Front-end knowledge
event delegation

Author : Li Juncai (jcLee95) : https://blog.csdn.net/qq_28550263
Email: [email protected]
Article address : https://blog.csdn.net/qq_28550263/article/details/132819265


【介绍】:本文介绍前端中的事件委托。

Previous section: " Previous section title " | Next section: " Next section title "


1. References

Consider the following question:

  • When we encounter a situation in front-end development where we need to bind event handlers to a group of similar elements , we usually face a question: Is it a good idea to create an independent event handler for each element ? ?

We will illustrate this problem and the concept of delegation through the following example.

【Problem Description】:

  • Suppose we have a web page that contains a shopping cart with many items, and each item has an "Add to Cart" button.
  • We want to be able to perform the same action when the user clicks on these buttons , which is to add an item to the cart and update the display of the cart.

One of the simplest ways is to bind click event handlers to each button individually , like this:

<ul id="cart">
  <li>
    <span>商品1</span>
    <button class="add-to-cart">添加到购物车</button>
  </li>
  <li>
    <span>商品2</span>
    <button class="add-to-cart">添加到购物车</button>
  </li>
  <!-- 更多商品项... -->
</ul>

<script>
const addToCartButtons = document.querySelectorAll('.add-to-cart');

addToCartButtons.forEach(button => {
      
      
  button.addEventListener('click', function() {
      
      
    // 执行添加到购物车的逻辑
    // 更新购物车显示
  });
});
</script>

Although the above code is functionally possible, it has a potential problem:

  • Create a separate event handler for each button.
  • As you can imagine - when there are a large number of products, a large number of similar function instances will be created, taking up a lot of memory.

2. Event bubbling

Event bubbling (Event Bubbling) means that when processing a DOM event, the event will start bubbling from the innermost element that triggered it, propagating upwards step by step, all the way to the root element (usually or) until it is stopped or canceled . This means that if a child element triggers an event, the event will also be passed down to the child element's parent element, and the parent element's parent element, and so on.

The workflow of event bubbling is as follows:

  1. First, the user triggers an event on an element on the page, such as clicking the mouse or touching the screen;
  2. The event is first dispatched to the innermost element that triggered the event (the target element) , and the bound event handler is executed on that element .
    3. The event then starts bubbling up , passing up to the upper element, triggering the same event on the parent element layer by layer ;
    4. When the event reaches the root of the document (usually the element), it may stop bubbling , or it may Continue to be passed to the browser level ( depending on whether the event is canceled ).

During this process, event handlers bound to any parent element may be triggered, including the target element's own parent element, grandparent element, great-grandfather element, and document root element.

3. Event bubbling is the basis for delegation.

In the case of Section 1, we mentioned a small flaw. In other words, creating a separate event handling function for each button may lead to the creation of a large number of similar function instances when there are a large number of products, occupying a large amount of memory.

At this time, we think of the bubbling mechanism:

  • The bubbling mechanism allows events to be passed through the DOM structure and captured by multiple elements . This allows us to capture events for child elements on the parent element, thereby reducing the number of event handlers and improving performance and maintainability.

In fact, the bubbling mechanism is also the basis of the event delegation model.

Combined with the case in Section 1, when the user clicks any "Add to Cart" button, the event will bubble up to

  • Element, we can handle events on the parent element and modify the modified part of the code as follows:

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

cart.addEventListener('click', function(event) {
      
      
  if (event.target.classList.contains('add-to-cart')) {
      
      
    // 执行添加到购物车的逻辑
    // 更新购物车显示
  }
});
</script>

The main difference between the modified script and the script in Section 1 is the location of event handling.

In Section 1, event handlers were bound directly to each "Add to Cart" button , using button.addEventListener. This means that each button has its own independent event handler, and when the user clicks one of the buttons, only the event handler associated with that button is fired:

addToCartButtons.forEach(button => {
    
    
  button.addEventListener('click', function() {
    
    
    // 执行添加到购物车的逻辑
    // 更新购物车显示
  });
});

In the modified script, the event handler is bound to the shopping cart container

  • on, used cart.addEventListener. Then, inside the event handler, a check is made event.targetto determine if the element that triggered the event contains the class name 'add-to-cart'. If so, execute the corresponding logic:

const cart = document.getElementById('cart');

cart.addEventListener('click', function(event) {
    
    
  if (event.target.classList.contains('add-to-cart')) {
    
    
    // 执行添加到购物车的逻辑
    // 更新购物车显示
  }
});

What are the benefits of this modification:

  • The former has its own event handler for each button, which is easier to understand logically, but when there are a large number of buttons, it will result in the creation of multiple function instances, which may take up more memory.
  • The latter only has one event handler bound to the shopping cart container, which reduces memory usage and improves performance because there is only one event handler instance.

The latter method of taking advantage of the bubbling characteristics of events and merging listeners of the same type from multiple child elements to the parent element is called event delegation.

4. Another scenario: event binding for dynamically generated elements

The idea of ​​event delegation can also be applied to listening to dynamically generated elements and dynamically binding events.

Dynamically generated elements are elements that are created through JavaScript code after the page is loaded - since these elements do not exist in the initial HTML, they cannot directly bind event handlers like static elements .

Let us explain in detail through a specific example - how to use event delegation to listen and handle events of dynamically generated elements.

Let's say we have a button that when clicked will dynamically create a new list item (<li> element) on the page, and then we want to be able to click on these dynamically created list items and perform some action, like change their style or something else operate. code show as below.

<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>动态元素事件委托案例</title>
</head>
<body>
  <ul id="dynamic-list">
    <!-- 这里没有任何<li>元素 -->
  </ul>
  <button id="add-button">添加列表项</button>

  <script>
    const dynamicList = document.getElementById('dynamic-list');
    const addButton = document.getElementById('add-button');

    // 点击按钮时,动态创建一个新的列表项
    addButton.addEventListener('click', function() {
      
      
      const newItem = document.createElement('li');
      newItem.textContent = '新的列表项';
      dynamicList.appendChild(newItem);
    });

    // 事件委托,监听<ul>上的点击事件
    dynamicList.addEventListener('click', function(event) {
      
      
      if (event.target.tagName === 'LI') {
      
      
        // 当点击列表项时,执行操作
        event.target.style.backgroundColor = 'lightblue';
      }
    });
  </script>
</body>
</html>

In this example, there is an add button (addButton) and an empty unordered list (dynamicList).

  • When the user clicks the button, a new list item (<li> element) is dynamically created and added to the list.

  • We use event delegation to bind the click event to the <ul> element and listen to the click events of all <li> elements.

Whenever a dynamically generated list item is clicked, an event bubbles up to the <ul> element, and the event handler checks to see if the clicked element is a <li> element, and if so, performs the appropriate action. In this example, we change the background color of the clicked list item. The effect is as shown in the figure:

Insert image description here

As you can see from this example, this way we can dynamically bind the event handler without having to manually bind it for each list item - so no matter how many list items there are, the code can handle it.

Guess you like

Origin blog.csdn.net/qq_28550263/article/details/132819265