Как реализовать обработку клика на любой div внутри root и выводить в консоль только id этого div в JavaScript
Что проверяют
Знаете ли вы делегирование событий и чем event.target отличается от event.currentTarget. Подвох в деталях: внутри div бывает текст в span, а сами div вложены друг в друга. Следом спрашивают, почему один обработчик на корне лучше сотни обработчиков на детях.
Как отвечать
Один обработчик вешается на #root, клик всплывает к нему от любого потомка. Внутри нужно найти div, по которому кликнули, даже если сработал вложенный элемент:
const root = document.getElementById('root');
root.addEventListener('click', (event) => {
const div = event.target.closest('div');
if (!div || div === root || !root.contains(div)) return;
console.log(div.id);
});Что здесь важно:
closest('div'): поднимается от цели клика вверх и возвращает ближайший div, включая сам элемент. Клик поspanвнутри div даст этот div;div === root: клик по пустому месту самого корня не считается кликом по div внутри root, его отсекаем;root.contains(div): страховка на случай, если root сам лежит внутри другого div, тогдаclosestможет выйти за его пределы;- вложенные div:
closestвернёт самый внутренний. Если по условию нужен прямой потомок root, поднимаются поparentElement, пока родителем не станет root.
Зачем делегирование: один обработчик вместо N, он работает для элементов, добавленных позже, и не нужно снимать обработчики при удалении узлов. Если у div нет id, в консоль уйдёт пустая строка, об этом стоит сказать и уточнить, выводить ли её.
Где спотыкаются
Проверяют event.target.tagName === 'DIV'. Стоит кликнуть по тексту в span или по иконке внутри div, и условие ложно, id не выводится.
Берут event.currentTarget вместо target. При делегировании это всегда сам корень, и в консоль каждый раз уходит «root».
Забывают, что делегирование держится на всплытии. Если дочерний обработчик вызывает stopPropagation(), до корня клик не дойдёт, а события вроде focus не всплывают вовсе, для них берут focusin.