Введение

Делегирование событий — это шаблон JavaScript, в котором дочерние элементы позволяют или оставляют родительские элементы обрабатывать события от их имени. Это возможно благодаря тому факту, что события в JavaScript могут всплывать (перемещаться) от дочерних элементов к родительским элементам. Таким образом, делегирование событий позволяет нам обрабатывать события в родительском элементе, а не в целевом элементе, который в данном случае является дочерним.

Проблема прослушивателя дочерних событий

Рассмотрим следующий фрагмент DOM.

<div class="container">
     <button>Button One</button> 
</div>

Для довольно простого варианта использования для обработки события нажатия на кнопку вы можете просто добавить прослушиватель событий на кнопку.

let button = document.getElementById("buttonOne");

button.addEventListener('click', (e)=>{
  console.log(e.target.innerText)
});

При нажатии на кнопку текст Button One будет зарегистрирован в консоли.

Что произойдет, если наш div будет содержать больше кнопок?

<div id="container">
     <button class="div-button">Button One</button>
     <button class="div-button">Button Two</button>
     <button class="div-button">Button Three</button>
     <button class="div-button">Button Four</button>
</div>

Добавление прослушивателей событий для каждой кнопки в div сделает наш код очень загроможденным и очень повторяющимся, мы могли бы немного улучшить это, используя метод querySelectorAll(). querySelectorAll() возвращает список узлов, который можно перебирать с помощью метода forEach().

let buttons = document.querySelectorAll(".div-button");

buttons.forEach(button =>{
    button.addEventListener('click', (e)=>{
      console.log(e.target.innerText);
  })
})

То, что происходит выше, заключается в том, что концептуально мы создали обработчики событий для каждой кнопки в div.

Пока это работает, это представляет собой проблему.

  1. что, если бы мы динамически добавили еще одну кнопку в этот div?

Динамическое добавление кнопки

Если бы мы динамически добавили еще одну кнопку в этот div и щелкнули по ней, ее внутренний текст не был бы зарегистрирован в консоли. Причина в том, что JavaScript регистрирует или связывает обработчики событий, когда DOM загружается в первый раз, и поскольку динамической или новой кнопки не было при загрузке DOM, ее события не будут зарегистрированы. Давайте посмотрим это в действии

<div id="container">
     <button class="div-button">Button One</button>
     <button class="div-button">Button Two</button>
     <button class="div-button">Button Three</button>
     <button class="div-button">Button Four</button>
</div>

<!-- add another button here outside the container -->
<button  id="addButton">Append a new button</button>

Мы добавили в документ новую кнопку, поэтому, когда пользователь нажимает на нее, к контейнеру div добавляется новая динамическая кнопка. Ниже приведен код JavaScript для этого.

const dynamic_btn = document.createElement("BUTTON");
dynamic_btn.innerHTML = "Dynamic Button";
dynamic_btn.class = "div-button";

let container_div = document.getElementById('container');

document.getElementById("addButton").addEventListener('click', (e)=>{
  container_div.appendChild(dynamic_btn);
})

Таким образом, при нажатии на новую динамическую кнопку ее внутренний текст не регистрируется в консоли.

Решение

Хотя нажатие на кнопку не записывает ее внутренний текст в консоль, ее событие по-прежнему запускается и распространяется через DOM. Таким образом, мы передадим событие родительскому элементу, и он его обработает, и это то, что касается делегирования событий, дочерние элементы передают свои события родительскому элементу.

Поэтому, чтобы решить эту проблему, мы просто переместим прослушиватель событий из списка узлов кнопок в контейнер div.

let container_div = document.getElementById('container');

container_div.addEventListener('click', (e)=>{
  console.log(e.target.innerText);
})

Теперь это решает нашу проблему, даже когда мы добавляем новые кнопки в div, мы по-прежнему можем регистрировать внутренний текст, и, следовательно, вы можете запускать с ними любое событие.

Заключение

Мы рассмотрели, что такое делегирование событий. Стоит отметить, что делегирование событий обеспечивается шаблоном всплытия событий в JavaScript, который, говоря простым языком, представляет собой возможность перемещать события вверх по дереву DOM от дочернего элемента к элементу документа.