Загрузка...

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

У кассы одна полоска. Родитель — #strip. На ней уже две кнопки: #red с текстом red и #blue с текстом blue. Под полоской #note говорит blank.
Не вешай слушателя на каждую кнопку. Один вызов addEventListener на полоске хватает. Клик кнопки внутри поднимается к полоске. event.target — эта кнопка. event.currentTarget — полоска, элемент, на котором сидит этот слушатель.
Кнопки #gold на странице ещё нет. Её создают после того, как слушатель сохранён, добавляют на полоску и кликают. Та же функция выполняется. Записка становится gold. Скрипт кликает red, потом blue, потом gold. addEventListener вызван один раз, поэтому hands равен 1. Строка под полоской: red / blue / gold / 1. У этих кнопок type="button". Здесь нет preventDefault и нет stopPropagation. Это была страница таблички, и там ребёнок после слушателя не добавлялся.

Один слушатель на все билеты

Страница таблички называла параметр event и читала type, target и currentTarget у ссылки внутри стены. Строка была click / seal / plaque / true / quiet. Вешалка хранила wool и silk без параметра. Строка была wool silk / 2 / peg. Здесь параметр event остаётся, но у target другая работа: сказать, какой ребёнок получил клик, даже если его ещё не было.
getElementById даёт только полоску, красную кнопку, синюю кнопку и записку. Gold рождается из createElement. Слушатель на red и ещё один на blue пропустят gold, если не повесить снова после appendChild. Одному слушателю на полоске вторая подвеска не нужна. Читай currentTarget внутри функции. После возврата это свойство равно null.

Что записывает полоска

Записка начинается с blank. Подписи остаются red и blue, gold приходит позже. Читай строки по порядку. Каждый фрагмент стартует с полоски из двух кнопок, кроме строки страницы — это демо внизу. Это демо вызывает addEventListener один раз.

📊 Что записывает полоска

Момент Что читаешь Текст записки Легко спутать
слушатель на полоске, клик по red event.target.id red читать currentTarget, это strip
тот же клик, читать currentTarget event.currentTarget.id strip читать id билета
тот же слушатель, клик по blue event.target.id blue дать blue свой слушатель
gold создан после слушателя и нажат event.target.id gold думать, что новая кнопка молчит
клик по самой полоске, со сторожем записка skip записать id strip
скрипт страницы строка red / blue / gold / 1 строка таблички или финальная 3

Клик по кнопке — одно событие. target остаётся этой кнопкой для каждого слушателя на пути. Здесь слушатель один, на полоске, поэтому пока функция идёт, currentTarget — полоска. Клик доходит, потому что никто не вызывает stopPropagation. Страница таблички этот путь обрывала. Эта страница не обрывает.
preventDefault нужен для действия браузера по умолчанию, например ухода по ссылке. Здесь кнопки, не ссылки. Отсутствие preventDefault — вся страница, а не пропущенная строка.
Если event.target и event.currentTarget — один и тот же узел, клик сел на полоску, не на кнопку. Функция пишет skip и не считает бумагу билетом. seen.join(" / ") склеивает только id, которые уже попали в seen. hands идёт после. Последний знак — сколько раз вызван addEventListener, а не сколько билетов нажато.

Билет под кликом

Слушатель на полоске. Функция называет параметр event и пишет event.target.id в записку. Потом страница кликает red. На red addEventListener не вызывается.

Прочитать билет

javascript
let strip = document.getElementById("strip");
let note = document.getElementById("note");
function take(event) {
note.textContent = event.target.id;
}
strip.addEventListener("click", take);
document.getElementById("red").click();
console.log(note.textContent);

Вывод — red. Элемент слушателя — полоска. target не сообщает родителя. Он сообщает кнопку под кликом.

Кому принадлежит слушатель

Свежая полоска, тот же слушатель, тот же клик по red. Записка пишет оба id: сначала target, потом currentTarget.

Прочитать оба id

javascript
let strip = document.getElementById("strip");
let note = document.getElementById("note");
function take(event) {
note.textContent = event.target.id + " " + event.currentTarget.id;
}
strip.addEventListener("click", take);
document.getElementById("red").click();
console.log(note.textContent);

Вывод — red strip. Первое слово — билет. Второе — элемент, которому принадлежит этот слушатель. Если слушатель сидит на самом red и кликнуть red, выйдет red red. Это чтение с полоски, поэтому id различаются.

Билет, который уже лежал рядом

Снова свежая полоска. Один слушатель, по-прежнему только на полоске. На этот раз клик — blue. Blue был в разметке с самого начала. Своего слушателя у него нет.

Услышать соседний билет

javascript
let strip = document.getElementById("strip");
let note = document.getElementById("note");
function take(event) {
note.textContent = event.target.id;
}
strip.addEventListener("click", take);
document.getElementById("blue").click();
console.log(note.textContent);

Вывод — blue. Один addEventListener покрыл обе кнопки, которые уже были внутри полоски. Blue не заменил red. Red не нужен был второй вызов.

Билет, напечатанный позже

Сначала слушатель сохраняется. Потом страница собирает кнопку, ставит id gold, type в button, текст gold и добавляет её на полоску. Только затем кликает gold.

Услышать поздний билет

javascript
let strip = document.getElementById("strip");
let note = document.getElementById("note");
function take(event) {
note.textContent = event.target.id;
}
strip.addEventListener("click", take);
let gold = document.createElement("button");
gold.id = "gold";
gold.type = "button";
gold.textContent = "gold";
strip.appendChild(gold);
gold.click();
console.log(note.textContent);

Вывод — gold. Gold не существовал, когда выполнялся addEventListener. Клик поднимается от gold к полоске, и target — это gold. На gold слушателя не вешают.

Клик по бумаге

Сама полоска тоже кликабельный узел. Если target клика — полоска, id билета сохранять нечего. Функция сравнивает target с currentTarget. Если они совпали, записка становится skip.

Пропустить клик по полоске

javascript
let strip = document.getElementById("strip");
let note = document.getElementById("note");
function take(event) {
if (event.target === event.currentTarget) {
note.textContent = "skip";
return;
}
note.textContent = event.target.id;
}
strip.addEventListener("click", take);
strip.click();
console.log(note.textContent);

Вывод — skip. И target, и currentTarget — полоска, поэтому сторож отвергает бумагу. Клик по red по-прежнему пишет red, потому что две ссылки разные. Без сторожа strip.click() запишет id strip в записку.

Строка под полоской

Скрипт стоит в конце body, когда полоска и абзацы уже есть. Сохраняется один слушатель, hands становится 1. Кликается red, затем blue. Id каждого билета попадает в seen. Gold создаётся, добавляется и кликается, поэтому gold тоже попадает в seen. Строка пишется после этого третьего клика. Страница не кликает саму полоску, поэтому skip в строке нет.

Демо страницы — полоска билетов

html
<!DOCTYPE html>
<html>
<head>
<title>event-delegation — page</title>
</head>
<body>
<div id="strip">
<button id="red" type="button">red</button>
<button id="blue" type="button">blue</button>
</div>
<p id="note">blank</p>
<p id="line">…</p>
<script>
let strip = document.getElementById("strip");
let note = document.getElementById("note");
let seen = [];
let hands = 0;
function take(event) {
if (event.target === event.currentTarget) {
note.textContent = "skip";
return;
}
note.textContent = event.target.id;
seen.push(event.target.id);
}
strip.addEventListener("click", take);
hands = hands + 1;
document.getElementById("red").click();
document.getElementById("blue").click();
let gold = document.createElement("button");
gold.id = "gold";
gold.type = "button";
gold.textContent = "gold";
strip.appendChild(gold);
gold.click();
document.getElementById("line").textContent =
seen.join(" / ") + " / " + hands;
</script>
</body>
</html>

Строка читается red / blue / gold / 1. Три id — это нажатые билеты, по порядку. Последний знак — hands. addEventListener выполнился один раз, поэтому знак равен 1, не 3. Записка заканчивается на gold, потому что последний клик был gold. Слово blank исчезло. Слово skip не появляется. Строка таблички и строка вешалки — другие страницы.
Кнопка, в которой только текст, оставляет event.target на кнопке, поэтому id равен red, blue или gold. span внутри кнопки может принять клик. У span нет id. Эта страница так не делает.

У кассы

  1. Повесь один слушатель на полоску и кликни red. Записка — red. У red нет своего слушателя.
  2. Тем же слушателем кликни blue. Записка — blue.
  3. Создай gold, добавь и кликни. Записка — gold. Слушатель уже был на полоске.
  4. Кликни саму полоску. Со сторожем записка — skip. Потом прочитай строку: red / blue / gold / 1.

Где у кассы ошибаются

Подписи по-прежнему говорят red, blue и gold. Записка — не слово «билет».

  • Слушатель на red и ещё один на blue, а потом удивление, что gold молчит
  • Читать event.currentTarget, когда нужен был билет
  • Читать event.target, когда нужна была полоска
  • Забыть сторожа, и тогда strip.click() пишет strip
  • span внутри кнопки, и тогда target — это span, а id пустой
  • Снова вызвать addEventListener на gold и посчитать hands как 2
  • Вызвать preventDefault или stopPropagation; это была страница таблички
  • Ждать, что аргумент функции — элемент кнопки
  • Читать строку как click / seal / plaque / true / quiet или как wool silk / 2 / peg
  • Читать последний знак как 3, потому что нажаты три билета

Что остаётся

  • Один addEventListener на полоске слышит каждую кнопку внутри
  • При клике red event.target.id равен red, а event.currentTarget.id равен strip
  • Тот же слушатель пишет blue, когда нажат blue
  • Gold, созданный после слушателя, всё равно пишет gold
  • Клик по самой полоске со сторожем пишет skip
  • Строка страницы: red / blue / gold / 1

🧠 Проверьте Свои Знания

Готов к Началу

Проверьте Свои Знания

Бросьте себе вызов с помощью этой интерактивной викторины и узнайте, насколько хорошо вы понимаете тему

❓
8
Вопросы
🎯
70%
Для Прохождения
♾️
∞
Время
🔄
∞
Попытки

📝 Инструкции

  • Внимательно прочитайте каждый вопрос
  • Выберите лучший ответ на каждый вопрос
  • Вы можете пересдавать тест столько раз, сколько захотите
  • Ваш прогресс будет показан вверху