Делегирование событий в JavaScript

В предыдущем уроке была описана проблема, возникающая при добавлении новых элементов, и приведено ее решение. В данном уроке мы рассмотрим более удачный способ обойти проблему - делегирование событий. Давайте его разберем.

Как вы уже знаете, кликая на li, мы одновременно кликаем и на ul. Это возможно благодаря всплытию событий. Мы можем использовать это для решения нашей задачи: навесим событие не на каждую li, а на их родителя ul:

list.addEventListener('click', function() { });

Теперь в обработчике события this будет указывать на элемент, к которому привязан обработчик, а event.target - на элемент, в котором случилось событие:

list.addEventListener('click', function(event) { console.log(this); // наш список console.log(event.target); // пункт списка });

Сделаем так, чтобы li, на которой случился клик, в конец добавлялся восклицательный знак:

list.addEventListener('click', function(event) { event.target.innerHTML = event.target.innerHTML + '!'; });

Повторите приведенное решение. Убедитесь, что новые li также будут реагировать на клик.

Универсальное делегирование событий

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

Недостаток нашего кода проявится в том случае, когда внутри li будут какие-то вложенные теги. В нашем случае пусть это будут теги i:

<ul> <li>item <i>italic</i> item</li> <li>item <i>italic</i> item</li> <li>item <i>italic</i> item</li> <li>item <i>italic</i> item</li> <li>item <i>italic</i> item</li> </ul>

В этом случае нажатие на тег i приведет к добавлению восклицательного знака в конец тега i, а не тега li, как мы хотели бы - ведь в event.target попадает именно тот тег, в котором случилось событие.

Решить проблему можно с помощью метода closest:

list.addEventListener('click', function(event) { let li = event.target.closest('li'); if (li) { li.innerHTML = li.innerHTML + '!'; } });

Повторите приведенное решение.