Введение
Делегирование событий — это шаблон 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.
Пока это работает, это представляет собой проблему.
- что, если бы мы динамически добавили еще одну кнопку в этот 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 от дочернего элемента к элементу документа.