Запропонувати правкуПокращити цю статтюДопрацюйте відповідь до «Різниця між event.target та event.currenttarget у JavaScript». Ваші зміни проходять модерацію перед публікацією.Потрібне підтвердженняКонтентЩо ви змінюєте🇺🇸EN🇺🇦UAПереглядЗаголовок (UA)Коротка відповідь (UA)**`event.target`** - це елемент, де подія виникла. **`event.currentTarget`** - це елемент, до якого прикріплений обробник. ```javascript parent.addEventListener('click', (e) => { // Клік на дочірній кнопці: console.log(e.target.id); // "child" console.log(e.currentTarget.id); // "parent" }); ``` **Ключове:** `target` не змінюється під час бабблінгу; `currentTarget` оновлюється на кожному обробнику.Показується над повною відповіддю для швидкого нагадування.Відповідь (UA)Зображення**`event.target`** - це елемент, на якому подія фактично виникла. **`event.currentTarget`** - це елемент, до якого прикріплений обробник події. ## Теорія ### TL;DR - `event.target` - звідки подія прийшла (кнопка, на яку натиснули всередині div). - `event.currentTarget` - де живе твій `addEventListener` (сам div). - Під час бабблінгу `target` не змінюється; `currentTarget` оновлюється на кожному обробнику. - Треба знати, що саме натиснули? Бери `target`. Треба елемент з обробником? Бери `currentTarget`. - Для делегування подій (event delegation) на динамічних списках - `target`. ### Швидкий приклад ```html <div id="parent" style="padding: 20px; background: lightblue;"> <button id="child">Click me</button> </div> ``` ```javascript const parent = document.getElementById('parent'); parent.addEventListener('click', (event) => { console.log(event.target.id); // "child" — натиснули кнопку console.log(event.currentTarget.id); // "parent" — обробник тут }); ``` Натискаєш кнопку: `target` вказує на кнопку, `currentTarget` на div. Обробник на div, але клік стався на кнопці всередині нього. ### Головна різниця Коли подія піднімається по DOM (бабблінг), `event.target` залишається прив'язаним до елемента, де подія виникла. А `event.currentTarget` оновлюється на кожному кроці і завжди відображає елемент, чий обробник зараз виконується. Якщо у тебе вкладені div-и з обробниками на кожному, `target` буде однаковим у всіх, а `currentTarget` у кожного свій. ### Коли що використовувати - **Динамічні дочірні елементи (делегування подій):** використовуй `target`. Прикріплюєш один обробник на батьківський `<ul>` і перевіряєш `e.target`, щоб знайти конкретний `<li>`. Працює навіть для елементів, доданих після завантаження сторінки. - **Власний елемент обробника:** використовуй `currentTarget`. Перемикання класу або читання розмірів елемента, до якого прикріплений обробник. - **Більше 10 динамічних дочірніх елементів:** делегування через `target` рятує від прикріплення окремих обробників до кожного. - **Один елемент з обробником:** `currentTarget` передбачуваний і не потребує додаткових перевірок. ### Таблиця порівняння | | `event.target` | `event.currentTarget` | |---|---|---| | Вказує на | Елемент, де виникла подія | Елемент з прикріпленим обробником | | Під час бабблінгу | Не змінюється | Оновлюється на кожному обробнику | | Дорівнює `this`? | Не завжди | Так (у звичайних функціях) | | Використовується для | Делегування, визначення джерела | Робота з елементом-власником обробника | ### Як браузер встановлює ці значення Браузер відправляє події згідно специфікації DOM Level 2/3: фаза захоплення (capture) вниз, фаза цілі (target), фаза бабблінгу вгору. Кожного разу, коли виконується обробник, рушій встановлює `currentTarget` на елемент, який зареєстрував цей конкретний обробник. `target` встановлюється один раз при відправці і більше не змінюється. Тому після `stopPropagation()` `target` все одно залишається початковим елементом. ### Типові помилки **Помилка: стилізувати `target`, коли потрібен елемент обробника** ```javascript // Обробник на div; користувач натискає вкладений img всередині div elem.addEventListener('click', (e) => { e.target.style.background = 'red'; // Фарбує img, а не div }); ``` Виправлення: `e.currentTarget.style.background = 'red'`. **Помилка: перемикати клас через `target` без перевірки** ```javascript parent.addEventListener('click', (e) => { e.target.classList.toggle('active'); // Перемикає на будь-якому дочірньому: span, p, img... }); ``` Виправлення: додай перевірку. `if (e.target.matches('button')) e.currentTarget.classList.toggle('active')`. **Помилка: вважати що `target === currentTarget` завжди** Вони рівні тільки коли натискаєш безпосередньо на елемент з обробником. Щойно клік потрапляє на дочірній елемент, вони розходяться. Це частий баг в обробниках закриття tooltip, де клік на span всередині wrapper закриває сам tooltip - бо обробник перевіряє `e.target` замість `e.currentTarget`. ### Де зустрічається - **React:** `SyntheticEvent.target` для делегування форм (читання `e.target.value` у спільному `onChange`). `currentTarget` для доступу до самого елемента форми. - **Vue:** `$event.target` всередині `v-on` для динамічного контенту слотів. - **Vanilla delegation:** один обробник на таблиці, `e.target.closest('tr')` щоб отримати натиснутий рядок. - **Міграція з jQuery:** патерни `$(event.target).closest()` перекладаються на vanilla через `e.target.closest()`. ### Питання на співбесіді **Q:** Що відбувається з `target` і `currentTarget` у фазі захоплення (capture)? **A:** Обидва встановлюються і під час capture. `currentTarget` відповідає елементу, що перехоплює, а `target` все одно залишається початковим джерелом події. **Q:** Чи змінює `stopPropagation()` значення `target`? **A:** Ні. `target` фіксується при відправці події. `stopPropagation()` тільки зупиняє переміщення події до наступного елемента в ланцюжку. **Q:** Чому `this` у звичайній функції-обробнику дорівнює `currentTarget`? **A:** Браузер встановлює `this` рівним `currentTarget` при виклику обробника. Стрілкові функції не мають власного `this`, тому там цей механізм не працює. **Q:** Що буде, якщо натиснути безпосередньо на елемент з обробником, без вкладених дочірніх? **A:** `target === currentTarget`. Вони розходяться тільки коли клік відбувається на дочірньому елементі. **Q:** У React Portal, на що вказує `target`? **A:** `target` вказує на дочірній елемент порталу. React перерозподіляє синтетичні події через дерево React-компонентів, тому делегування працює навіть через межу порталу. ## Приклади ### Делегування подій на динамічному списку ```javascript const list = document.getElementById('list'); // Один обробник покриває всі елементи, включно з тими, що додаються пізніше list.addEventListener('click', (e) => { if (e.target.tagName === 'LI') { console.log('Натиснуто:', e.target.textContent); e.target.classList.toggle('selected'); } // e.currentTarget завжди є елементом #list }); // Цей новий елемент одразу працює — без додаткового обробника const newItem = document.createElement('li'); newItem.textContent = 'Новий елемент'; list.appendChild(newItem); ``` Один обробник на батьківському елементі охоплює всі пункти, поточні і майбутні. `e.target` повідомляє, який конкретний пункт натиснули; `e.currentTarget` завжди вказує на список. ### Форма зі спільним обробником, який використовує обидві властивості ```javascript const form = document.getElementById('signup-form'); form.addEventListener('change', (e) => { const field = e.target; // Яке поле змінилось const formEl = e.currentTarget; // Елемент форми console.log('Назва поля:', field.name); console.log('Нове значення:', field.value); // Перевірка всієї форми через елемент форми const allInputs = formEl.querySelectorAll('input'); const allFilled = [...allInputs].every(i => i.value.trim() !== ''); formEl.querySelector('#submit').disabled = !allFilled; }); ``` `e.target` визначає, яке поле змінилось. `e.currentTarget` дає доступ до всієї форми для повторної перевірки. Обидві властивості виконують різну роботу в одному обробнику.Для рев’юераПримітка для модератора (необов’язково)Бачить лише модератор. Прискорює рев’ю.