Что такое делегирование событий? И зачем она нам нужна?!

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

Мы можем сделать это, используя:

  • объект события и его свойство .target
  • различные фазы события (Захват / У цели / Бульканье).

Это может звучать как «Ха!», поэтому давайте поищем пример и вернемся сюда позже!

На конкретном примере мы покажем, почему это СУПЕР полезно!

Представьте, что есть <div>, который имеет 200 дочерних элементов параграфов, и при нажатии на любой из <p> тегов из них, мы хотим console.log какое-то сообщение!
Поэтому сначала мы можем написать код следующим образом:

const myCustomDiv = document.createElement('div');

for (let i = 1; i <= 200; i++) {
    const newElement = document.createElement('p');
    newElement.textContent = 'This is paragraph number ' + i;

    newElement.addEventListener('click', function respondToTheClick() {
        console.log('A paragraph was clicked.');
    });

    myCustomDiv.appendChild(newElement);
}

document.body.appendChild(myCustomDiv);
Войти в полноэкранный режим Выйти из полноэкранного режима

Есть несколько способов рефакторинга этого кода. Например, на данный момент мы создаем 200 различных respondToTheClick() (которые на самом деле делают одно и то же!). Мы можем извлечь эту функцию и просто ссылаться на нее, вместо того чтобы создавать двести различных функций:

const myCustomDiv = document.createElement('div');

function respondToTheClick() {
    console.log('A paragraph was clicked.');
}

for (let i = 1; i <= 200; i++) {
    const newElement = document.createElement('p');
    newElement.textContent = 'This is paragraph number ' + i;

    newElement.addEventListener('click', respondToTheClick);

    myCustomDiv.appendChild(newElement);
}

document.body.appendChild(myCustomDiv);
Вход в полноэкранный режим Выход из полноэкранного режима

Итак, мы произвели рефакторинг количества слушателей событий, написав 1 функцию вместо того, чтобы писать ее 200 раз!

Однако у нас по-прежнему двести слушателей событий. Все они указывают на одну и ту же функцию-слушатель, но у нас по-прежнему двести различных слушателей событий.
Что если вместо этого переместить все слушатели в <div>?

const myCustomDiv = document.createElement('div');

function respondToTheClick() {
    console.log('A paragraph was clicked.');
}

for (let i = 1; i <= 200; i++) {
    const newElement = document.createElement('p');
    newElement.textContent = 'This is paragraph number ' + i;

    myCustomDiv.appendChild(newElement);
}

myCustomDiv.addEventListener('click', respondToTheClick);

document.body.appendChild(myCustomDiv);
Вход в полноэкранный режим Выход из полноэкранного режима

Теперь есть только

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

Однако вы заметите, что мы потеряли доступ к отдельным абзацам. Мы не можем нацелиться на конкретный элемент абзаца. Как же нам совместить этот эффективный код с доступом к отдельным элементам абзаца, как это было в первом коде?

Мы используем делегирование события процесса.

const myCustomDiv = document.createElement('div');

function respondToTheClick(evt) {
    console.log('A paragraph was clicked: ' + evt.target.textContent);
}

for (let i = 1; i <= 200; i++) {
    const newElement = document.createElement('p');
    newElement.textContent = 'This is paragraph number ' + i;

    myCustomDiv.appendChild(newElement);
}

document.body.appendChild(myCustomDiv);

myCustomDiv.addEventListener('click', respondToTheClick);
Вход в полноэкранный режим Выход из полноэкранного режима

Почти идеально!
Просто нет ничего, чтобы убедиться, что это действительно был тег <p>, который был нажат перед консольным сообщением. Представьте, что у 200 <p> тегов есть разные братья и сестры, или родительский <div> элемент имеет некоторую прокладку, а мы не щелкнули на фактическом <p> теге!

Решение? Мы должны проверить тип узла.

if (evt.target.nodeName === 'P') {} или (evt.target.nodeName.toLowerCase() === 'p') {}.

Обратите внимание, что:

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

  • проверить наличие заглавных букв
  • преобразовать .nodeName в строчные буквы.

Вся заслуга в этом: Udacity и ее программе nanodegree.

счастливого кодинга!

Оцените статью
devanswers.ru
Добавить комментарий