Всплытие события можно остановить на любой
элемент, через который всплывает событие.
Для этого в коде элемента следует вызвать
метод stopPropagation
объекта Event
.
В следующем примере клик по красному блоку сработает на нем самом, затем на голубом блоке и все - голубой блок прекращает дальнейшее всплытие и зеленый блок уже никак не отреагирует:
elem1.addEventListener('click', function() {
alert('зеленый');
});
elem2.addEventListener('click', function(event) {
alert('голубой');
event.stopPropagation(); // остановим всплытие
});
elem3.addEventListener('click', function() {
alert('красный');
});
Можете проверить:
Несколько обработчиков на элементе
Если у элемента есть несколько обработчиков
на одно событие, то даже при прекращении
всплытия все они будут выполнены. То есть,
stopPropagation
препятствует продвижению
события дальше, но на текущем элементе все
обработчики отработают. Смотрите пример:
elem1.addEventListener('click', function() {
alert('зеленый');
});
elem2.addEventListener('click', function(event) {
alert('голубой - первый обработчик');
event.stopPropagation(); // остановим всплытие
});
elem2.addEventListener('click', function() {
alert('голубой - второй обработчик'); // все равно сработает
});
elem3.addEventListener('click', function() {
alert('красный');
});
Можете проверить:
Немедленное прекращение всплытия
Для того, чтобы полностью остановить обработку,
современные браузеры поддерживают метод stopImmediatePropagation
.
Он не только предотвращает всплытие, но и
останавливает обработку событий на текущем
элементе. Давайте его применим:
elem1.addEventListener('click', function() {
alert('зеленый');
});
elem2.addEventListener('click', function(event) {
alert('голубой - первый обработчик');
event.stopImmediatePropagation(); // остановим всплытие
});
elem2.addEventListener('click', function() {
alert('голубой - второй обработчик'); // уже не сработает
});
elem3.addEventListener('click', function() {
alert('красный');
});
Можете проверить:
Практическое применение
Пусть внутри одного родителя у нас есть кнопка и некоторый блок:
<div id="parent">
<button>click me</button>
<div id="block">
text
</div>
</div>
Получим ссылки на наши элементы в переменные:
let parent = document.querySelector('#parent');
let button = document.querySelector('button');
let block = document.querySelector('#block');
Пусть наш блок изначально скрыт:
#block:not(.active) {
display: none;
}
Сделаем так, чтобы по клику на кнопку наш блок показался:
button.addEventListener('click', function() {
block.classList.add('active');
});
А теперь сделаем так, чтобы по клику на любое место родителя наш блок скрывался:
parent.addEventListener('click', function() {
block.classList.remove('active');
});
Нас, однако, ждет неожиданный сюрприз: так как кнопка находится внутри родителя, то клик по кнопке одновременно означает и клик по родителю. Это значит, что сначала наш блок покажется, а затем из-за всплытия события сработает обработчик в родителе и наш блок скроется.
Вот тут-то нам и пригодится возможность отменить всплытие: мы можем сделать так, чтобы при клике на кнопку отменить всплытие, родитель не реагировал на этот клик.
Самостоятельно реализуйте корректную работу описанной задачи.