В предыдущем уроке была описана проблема, возникающая при добавлении новых элементов, и приведено ее решение. В данном уроке мы рассмотрим более удачный способ обойти проблему - делегирование событий. Давайте его разберем.
Как вы уже знаете, кликая на 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 + '!';
}
});
Повторите приведенное решение.