Что делает метод stopPropagation и как он влияет на обработку событий в DOM
Что проверяют
Различаете ли вы остановку распространения и отмену действия по умолчанию, и понимаете ли, чем опасно злоупотребление.
Как отвечать
Прямой способ это event.stopPropagation(). Он останавливает дальнейшее движение события по цепочке: обработчики на родителях не выполнятся.
Рядом два метода, которые с ним путают:
stopImmediatePropagation()дополнительно отменяет остальные обработчики на том же элементе, а не только на родителях;preventDefault()отменяет действие браузера по умолчанию (переход по ссылке, отправка формы) и на распространение не влияет вовсе. Это совершенно другая задача.
Пример правильного применения: кнопка удаления внутри кликабельной карточки. Нажатие на кнопку не должно открывать карточку.
Однако часто есть более аккуратная альтернатива, и её стоит назвать: вместо остановки распространения проверить источник события.
card.addEventListener("click", (e) => {
if (e.target.closest(".delete-button")) return;
openCard();
});Почему это лучше: stopPropagation невидимо ломает чужой код. Обработчик закрытия выпадающего меню по клику вне, аналитика на уровне документа, делегирование событий и сторонние библиотеки перестают получать событие, и причину такого поведения ищут долго.
Про React есть отдельная тонкость: события там синтетические и вешаются на корень приложения. Поэтому stopPropagation внутри React не остановит нативный обработчик, повешенный выше через addEventListener. Для этого нужен event.nativeEvent.stopPropagation().
И общее напоминание про фазы: событие сначала идёт вниз (погружение), потом обратно вверх (всплытие). Обработчик по умолчанию слушает всплытие, поэтому останавливать его надо на нужном уровне.
Где спотыкаются
Ставят preventDefault вместо stopPropagation.
Ставят stopPropagation везде и ломают делегирование и закрытие меню.
Ожидают, что stopPropagation в React остановит внешний нативный обработчик.
Не знают про stopImmediatePropagation и удивляются срабатыванию соседнего обработчика.