Делегирование событий: эффективная обработка множества элементов
Почему делегирование — это мощный инструмент? ️
Когда на странице сотни кнопок, карточек или других интерактивных элементов, вешать обработчик на каждый — плохая идея. Это съедает память и тормозит страницу.
Делегирование событий решает проблему: вместо множества обработчиков мы используем один на общего родителя. События «всплывают» (bubbling) от элемента к родителю, и мы ловим их там.
// Плохо: 100 обработчиков для 100 кнопок
document.querySelectorAll('.btn').forEach(btn => {
btn.addEventListener('click', () => {
console.log('Клик!');
});
});
// Хорошо: 1 обработчик на родителя
document.querySelector('.btn-container').addEventListener('click', (event) => {
if (event.target.classList.contains('btn')) {
console.log('Клик по кнопке!');
}
});
🔥 Секрет эффективности: Вместо 100 слушателей — один. Меньше нагрузки, проще масштабировать!
Как работает всплытие событий? 🌊
Когда происходит клик (или другое событие), оно проходит три фазы:
1. Capture — сверху вниз до целевого элемента.
2. Target — достижение элемента.
3. Bubbling — снизу вверх обратно к корню.
Делегирование использует bubbling. Даже если элемент добавлен динамически, событие «дойдет» до родителя.
document.getElementById('list').addEventListener('click', (event) => {
// Проверяем, был ли клик по элементу списка
if (event.target.tagName === 'LI') {
console.log('Клик по li:', event.target.textContent);
}
});
💡 Проверяйте
event.target— это исходный элемент, на котором произошло событие.
Практика: делегирование в реальных проектах ️
Пример 1: Динамически добавляемые элементы
Допустим, у нас есть список задач, куда можно добавлять новые элементы. Без делегирования новые элементы не будут обрабатывать клики.
// HTML: <ul id="tasks"></ul>
const taskList = document.getElementById('tasks');
// Добавляем задачи динамически
function addTask(text) {
const li = document.createElement('li');
li.textContent = text;
taskList.appendChild(li);
}
// Вешаем ОДИН обработчик на список
taskList.addEventListener('click', (event) => {
if (event.target.tagName === 'LI') {
event.target.classList.toggle('completed');
}
});
// Добавляем задачи
addTask('Изучить делегирование');
addTask('Сделать проект');
Пример 2: Универсальный обработчик для таблицы
Таблица с кнопками удаления строк. Вместо обработчика на каждую кнопку — один на всю таблицу.
document.querySelector('table').addEventListener('click', (event) => {
if (event.target.classList.contains('delete-btn')) {
const row = event.target.closest('tr');
row.remove();
}
});
🚀
closest()— ваш друг — ищет ближайший родительский элемент, подходящий под селектор.
Когда делегирование не подходит? ⚠️
- События без всплытия — например,
focus,blur. - Высокая вложенность — если элементов много, проверка
event.targetможет стать сложной. - Необходимость прервать всплытие — если где-то есть
stopPropagation(), делегирование может сломаться.
Итог: 3 причины использовать делегирование
- Экономия памяти — один обработчик вместо сотен.
- Работа с динамическими элементами — не нужно перевешивать слушатели.
- Чистый код — логика обработки событий централизована.
// Финал: универсальный шаблон для делегирования
parentElement.addEventListener('event', (e) => {
if (e.target.matches('селектор')) {
// Ваш код здесь...
}
});
Теперь — в бой! Попробуйте переписать свой проект с делегированием и почувствуйте разницу. 😎