Event Bubbling и Event Capturing в Javascript
Оригинальная статья: Afraz Momin — Event Bubbling and Event Capturing in Javascript
Интерактивность HTML-страницы создается благодаря Javascript. Эта интерактивность — не что иное, как куча событий, которые отслеживаются на HTML элементах. Событие может инициироваться браузером, или пользователем. Произошедшие события говорят нам, что были некоторые изменения и мы можем понять где они произошли. Это может быть событие onClick, которое указывает на то, что что-то было нажато. Другим примером может быть событие onSubmit, которое сообщает, что была отправлена некая форма.
Насколько хорошо обрабатываются эти события, определяет, насколько удобна веб-страница.
Event Bubbling и Event Capturing — это две фазы распространения событий в Javascript. Поток событий — это в основном порядок, в котором события обрабатываются на веб-странице. В Javascript поток событий происходит в три этапа:
- Capture Phase (Фаза распространения сверху вниз)
- Target Phase (Фаза цели)
- Bubble Phase (Фаза распространения снизу вверх)
Это распространение является двунаправленным, от window до target и обратно. Эти фазы могут отличается типом слушателей (listeners), которые вызываются.
Давайте начнем с рассмотрения фазы Bubbling.
Event Bubbling
Bubbling — это поток событий, при котором, сначала запускает обработчик на элементе, затем на родительском элементе и затем на всех предков элемента.
Он в основном перемещается вверх по иерархии от самого внутреннего элемента к внешнему элементу.
Это может быть лучше понято на примере —
<body> <div id="grandparent"> <p>Grandparent</p> <div id="parent"> <p>Parent</p> <div id="child"> <p>Child</p> </div> </div> </div> <button onClick="history.go(0)"> Reset Elements </button> </body>
В нашем HTML-файле мы берем 3 div, вложенных друг в друга, и присваиваем им идентификаторы child, parent и grandparent, начиная с самого внутреннего div.
Add a bit of styling
div { min-width: 75px; min-height: 75px; padding: 25px; border: 1px solid black; } button { margin-top: 20px; width: 200px; font-size: 14px; padding: 10px; }
Мы установим обработчик событие клика для каждого из 3-х div в нашем файле JS
document.querySelector("#grandparent").addEventListener("click", () => { document.querySelector("#grandparent > p").textContent = "Grandparent Clicked!"; console.log("Grandparent Clicked"); }); document.querySelector("#parent").addEventListener("click", () => { document.querySelector("#parent > p").textContent = "Parent Clicked!"; console.log("Parent Clicked"); }); document.querySelector("#child").addEventListener("click", () => { document.querySelector("#child > p").textContent = "Child Clicked!"; console.log("Child Clicked"); });
Код выше будет работать следующим образом —
Обратите внимание, что даже при клике на элементе child запускаются обработчики всех его предков. Аналогичным образом, при клике по родительскому элементу parent также будет запущен обработчик элемента grandparent родительского элемента. Но обратите внимание, что тогда обработчик дочернего элемента child не будет запущен.
Хотя здесь важнее то, как происходил поток событий. Он начинался с самого внутреннего элемента, то есть дочернего элемента child, а затем распространялся вверх по иерархии, в конечном итоге достигая элементов parent и grandparent (строго в этом порядке).
Такой тип потока событий называется Event Bubbling.
Event Capturing
Capturing является полной противоположностью bubbling.
В Event Capturing распространение события происходит от самого внешнего элемента до самого внутреннего элемента. Event Capturing иногда также называют event trickling.
Мы часто используем addEventListener() при работе с Javascript, в котором мы обычно передаем два параметра —
- Имя события
- Функцию обработки
Функция addEventListener() также принимает третий скрытый параметр — useCapture, который принимает логическое значение. Этот параметр useCapture по умолчанию имеет значение false. Если установить значение false, наши события будут распространяться по принципу Bubbling. Установка его в true заставит их распространяться в нисходящем подходе, то есть Capturing.
Для реализации Event Capturing мы внесем несколько небольших изменений в наш код JS —
document.querySelector("#grandparent").addEventListener("click", () => { document.querySelector("#grandparent > p").textContent = "Grandparent Clicked!"; console.log("Grandparent Clicked"); }, true); // Параметр useCapture теперь имеет значение true document.querySelector("#parent").addEventListener("click", () => { document.querySelector("#parent > p").textContent = "Parent Clicked!"; console.log("Parent Clicked"); }, true); // Параметр useCapture теперь имеет значение true document.querySelector("#child").addEventListener("click", () => { document.querySelector("#child > p").textContent = "Child Clicked!"; console.log("Child Clicked"); }, true); // Параметр useCapture теперь имеет значение true
Теперь наш код будет работать следующим образом —
Обратите внимание, как поток событий теперь распространяется от самого внешнего элемента к самому внутреннему элементу.
то есть grandparent
-> parent
-> child
Такой поток событий называется Event Capturing.
Заключение
Javascript помогает нам создавать интерактивные веб-приложения. При этом используется множество пользовательских событий. Пользовательский опыт веб-сайта зависит от того, насколько хорошо эти события обрабатываются. Следовательно, важно знать, как работают события и как они движутся.
Вот ссылка на Codepen, если вы хотите увидеть это самостоятельно.
Если вам понравилось то, что вы прочитали, следите за мной в Twitter — @afraz_momin, чтобы быть в курсе новых статей.
Я планирую написать подобные статьи о JavaScript в ближайшие дни!