Запропонувати правкуПокращити цю статтюДопрацюйте відповідь до «Делегування подій (Event Delegation)». Ваші зміни проходять модерацію перед публікацією.Потрібне підтвердженняКонтентЩо ви змінюєте🇺🇸EN🇺🇦UAПереглядЗаголовок (UA)Коротка відповідь (UA)**Делегування подій це прийом, коли обробник вішають не на кожен елемент, а на їхнього спільного батька, і за допомогою спливання подій визначають, на якому саме елементі сталася дія.** Один слухач керує подіями безлічі дочірніх елементів: це менше обробників у пам'яті, робоча логіка в одному місці і підтримка елементів, доданих динамічно. ```javascript document.body.addEventListener('click', (event) => { if (event.target.matches('button')) { console.log('clicked'); } }); ``` **Ключове:** делегування тримається на спливанні, а конкретний елемент визначається через `event.target`.Показується над повною відповіддю для швидкого нагадування.Відповідь (UA)Зображення**Делегування подій це прийом у JavaScript, коли ми вішаємо обробник не на кожен елемент, а на їхнього спільного батька, і використовуємо спливання подій, щоб визначити, на якому саме елементі сталася дія.** Іншими словами: один слухач керує подіями багатьох дочірніх елементів. ## Теорія ### TL;DR - Один обробник на батьківському елементі замість сотні обробників на дітях. - Працює завдяки спливанню: подія від дитини піднімається до батька, де її й ловлять. - Конкретний елемент визначається через `event.target`, зазвичай за допомогою `matches()` або `closest()`. - Автоматично охоплює елементи, додані в DOM пізніше. - Не працює для подій, які не спливають (`focus`, `blur`, `mouseenter`, `mouseleave`). ### Швидкий приклад Треба обробити кліки по 100 кнопках. Наївно, слухач на кожній кнопці: ```javascript document.querySelectorAll('button').forEach(btn => { btn.addEventListener('click', () => { console.log('clicked'); }); }); ``` Правильно, делегування: ```javascript document.body.addEventListener('click', (event) => { if (event.target.matches('button')) { console.log('clicked'); } }); ``` ### Навіщо це потрібно Ключові тези, які варто назвати на співбесіді: - **Менше обробників,** отже менше пам'яті і швидша робота сторінки. - **Працює для динамічно доданих елементів:** навіть якщо елемент з'явився пізніше, батьківський обробник його все одно «спіймає». - **Краща керованість:** уся логіка в одному місці, а не розмазана по дереву DOM. - **Простіше прибирання:** щоб від'єднати обробку, достатньо зняти один слухач, а не обходити всі вузли. ### Як це працює 1. Користувач клікає по кнопці. 2. Подія спливає вгору по дереву DOM. 3. Обробник на `body` (або на будь-якому спільному предку) перехоплює подію. 4. Ми перевіряємо `event.target`, щоб визначити елемент-кандидат. Надійніший варіант перевірки, коли всередині кнопки є вкладена розмітка (іконка, `<span>`): ```javascript list.addEventListener('click', (event) => { const item = event.target.closest('li'); if (!item || !list.contains(item)) return; console.log('Клік по пункту:', item.dataset.id); }); ``` `closest()` піднімається від фактичної цілі вгору, поки не знайде відповідний елемент, тож клік по іконці всередині пункту теж спрацює правильно. ### target проти currentTarget Це найчастіша помилка на співбесіді: - `event.target` це елемент, по якому клікнули, тобто джерело події. - `event.currentTarget` це елемент, на якому висить слухач, тобто батько. | Властивість | На що вказує | У делегуванні | | --- | --- | --- | | `event.target` | Реальна ціль події | Дочірній елемент, який нас цікавить | | `event.currentTarget` | Елемент зі слухачем | Батьківський контейнер | Усередині звичайної функції-обробника `this` дорівнює `event.currentTarget`, а не `target`. ### Коли делегування не підходить - **Подія не спливає.** Для `focus` і `blur` беріть `focusin` і `focusout`, для `mouseenter` і `mouseleave` беріть `mouseover` і `mouseout`. - **Хтось на шляху викликав `stopPropagation()`.** Тоді подія просто не дійде до батьківського слухача, і делегування мовчки перестане працювати. - **Дуже гарячі події на великому контейнері.** Для `mousemove` чи `scroll` один обробник на `document` може стати вузьким місцем, там краще точкові слухачі або throttling. > Коротке визначення, якщо інтерв'юер просить стисло: делегування подій це техніка, коли один обробник на батьківському елементі обробляє події багатьох дочірніх елементів, використовуючи спливання подій. ### Типові помилки - **Плутати `target` і `currentTarget`,** а потім дивуватися, чому перевірка завжди дає батьківський контейнер. - **Перевіряти лише `event.target.matches(...)`** там, де ціль може бути вкладеним вузлом. Використовуйте `closest()`. - **Вішати слухач одразу на `document` без потреби.** Беріть найближчого спільного предка: менше зайвих спрацювань і менше конфліктів з іншим кодом. - **Забувати перевірити, що знайдений елемент справді всередині контейнера.** Без `container.contains(item)` можна зловити збіг із чужого блока. - **Розраховувати на делегування для подій, які не спливають,** і потім довго шукати, чому обробник не викликається.Для рев’юераПримітка для модератора (необов’язково)Бачить лише модератор. Прискорює рев’ю.