Выбрать главу

Поехали!

Как все это делается?

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

Представьте, что есть случай, в котором вы хотите прослушивать событие клика в любом из элементов-братьев со значениями idone, two, three, four и five. Давайте дорисуем картину, изобразив DOM следующим образом:

В самом низу расположены элементы, в которых мы хотим прослушивать события. Все они имеют одного родителя в виде элемента с id, равным theDude. Чтобы разрешить проблему обработки этих событий, давайте рассмотрим сначала плохое решение, а затем его удачную альтернативу.

Плохое решение

Так делать не нужно. Мы не хотим создавать слушателя событий для каждой из кнопок:

let oneElement = document.querySelector("#one");

let twoElement = document.querySelector("#two");

let threeElement = document.querySelector("#three");

let fourElement = document.querySelector("#four");

let fiveElement = document.querySelector("#five");

oneElement.addEventListener("click", doSomething, false);

twoElement.addEventListener("click", doSomething, false);

threeElement.addEventListener("click", doSomething, false);

fourElement.addEventListener("click", doSomething, false);

fiveElement.addEventListener("click", doSomething, false);

function doSomething(e) {

let clickedItem = e.target.id;

console.log("Hello " + clickedItem);

}

Очевидная причина так не делать — в нежелании повторять код. Другая причина состоит в том, что для каждого элемента теперь установлено свойство addEventListener. В случае с пятью элементами это не так страшно. Однако все становится куда серьезнее, когда вы работаете с десятками или сотнями элементов, каждый из которых задействует частичку памяти. Еще одна причина в том, что число элементов может варьировать в зависимости от степени адаптивности или динамичности UI. Ваше приложение может добавлять или удалять элементы в зависимости от действий пользователя, что затруднит отслеживание всех индивидуальных слушателей событий, которые могут потребоваться объекту. Наличие же одного всеобщего обработчика событий существенно упрощает весь этот процесс.

Хорошее решение

Хорошее решение вторит схеме, приведенной ранее, где мы используем всего один слушатель событий. Сначала я вас немного запутаю описанием того, как это работает, а затем попытаюсь распутать, приведя пример кода и подробно пояснив все происходящее. Простое и запутывающее решение:

1. Создать один слушатель событий в родительском элементе theDude.

2. Когда произойдет щелчок по любому из элементов one, two, three, four или five, опереться на поведение распространения, присущее событиям, и прерывать их, когда они достигают элемента theDude.

3. (По желанию) Остановить распространение события в родительском элементе, чтобы оно не отвлекало нас своей безудержной беготней по дереву DOM вверх и вниз.

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

Последним этапом нашего квеста по распутыванию будет код, подробно расписывающий содержимое схемы и все три шага:

let theParent = document.querySelector("#theDude");

theParent.addEventListener("click", doSomething, false);

function doSomething(e) {

if (e.target!= e.currentTarget) {

let clickedItem = e.target.id;

console.log("Hello " + clickedItem);

}

e. stopPropagation();

}

Уделите время и внимательно прочитайте и проанализируйте этот код. Приняв во внимание наши изначальные цели и схему, мы будем слушать событие в родительском элементе theDude:

let theParent = document.querySelector("#theDude");

theParent.addEventListener("click", doSomething, false);

Обработкой этого события занимается один обработчик, которым является функция doSomething:

function doSomething(e) {

if (e.target!= e.currentTarget) {

let clickedItem = e.target.id;

console.log("Hello " + clickedItem);

}

e. stopPropagation();

}

Этот слушатель событий будет вызван каждый раз, когда будет происходить щелчок как в самом элементе theDude, так и в любом из его потомков. Нас же интересуют только события щелчка потомков. Правильным способом игнорировать щелчки по родительскому элементу будет просто избежать выполнения любого кода, если элемент, на котором произошел щелчок (то есть целевое событие), совпадает со слушателем событий (то есть элементом theDude):