Выбрать главу

Часть, в которой вы инициируете событие и оно, начиная с корня, совершает спуск вниз по DOM, называется фазой погружения события.

Менее продвинутые люди иногда называют его фаза 1, так что имейте в виду, что в реальной жизни вы будет встречать верное название вперемешку с названием фазы. Следующей будет фаза 2, во время которой событие всплывает обратно к корню.

Эта фаза также известна как фаза всплытия события.

Как бы то ни было, но всем элементам на пути события в некотором смысле повезло. Судьба наградила их возможностью двойного уведомления при срабатывании события. Это может повлиять на код, который вы пишете, так как каждый раз, когда мы прослушиваем события, решаем, в какой фазе нужно это делать. Слушаем ли мы событие во время его спуска в фазе погружения или же тогда, когда оно взбирается обратно в фазе всплытия?

Выбор фазы — это тонкая деталь, которую вы определяете с помощью true или false в вызове addEventListener:

item.addEventListener("click", doSomething, true);

Если вы помните, в предыдущей главе я вскользь упомянул третий аргумент — addEventListener. Этот аргумент указывает, хотите ли вы прослушивать событие во время фазы погружения. В этом смысле значение true означает, что именно так вы и хотите. И наоборот, аргумент false будет означать, что нужно прослушивать событие во время фазы всплытия.

Чтобы прослушивать его в обеих фазах, можно сделать следующее:

item.addEventListener("click", doSomething, true);

item.addEventListener("click", doSomething, false);

Я не могу представить, зачем вам это может понадобиться, но если вдруг понадобится, вы знаете, что делать.

не указана фаза

Можно возмутиться и вообще не указывать этот третий аргумент для фазы:

item.addEventListener("click", doSomething);

Если вы не укажете третий аргумент, то поведением по умолчанию будет прослушивание вашего события во время фазы восходящей цепочки. Это эквивалентно передаче в качестве аргумента ложного значения.

Кому это важно?

Вы можете спросить: «А почему это все важно?» Такой вопрос вдвойне справедлив, если вы и так давно работали с событиями и только сейчас обо всем этом прочитали. Выбор в пользу прослушивания события во время погружения или всплытия по большей части не зависит от того, что вы делаете. Очень редко может возникнуть путаница, когда код, отвечающий за прослушивание и обработку событий, делает не то, что нужно, так как вы случайно указали true вместо false в вызове addEventListener.

Этим я лишь хочу сказать, что в жизни может возникнуть ситуация, когда потребуется разбираться в фазах погружения/всплытия и работать с ними. Ошибка прокрадется в ваш код и выльется в многочасовое чесание затылка в поисках решения. Я могу привести список ситуаций из своей практики, когда мне пришлось осознанно выбирать фазу, в которой я наблюдал за событиями:

1. Перетаскивание элемента по экрану и обеспечение продолжения перетаскивания, даже если перемещаемый элемент выскользнет из-под курсора.

2. Вложенные меню, открывающие подменю при наведении на них указателя.

3. Есть несколько обработчиков событий в обеих фазах, а вы хотите сфокусироваться только на обработчиках в фазе погружения или всплытия.

4. Сторонний компонент и библиотека элементов управления имеют свою логику событий, и вы хотите обойти ее, чтобы использовать собственную настройку поведения.

5. Вы хотите переназначить предустановленное поведение браузера, например, когда вы нажимаете на полосу прокрутки или переключаетесь на текстовое поле.

За мои уже почти 105 лет работы с JavaScript могу привести только такие примеры. И даже они уже не столь однозначны, поскольку некоторые браузеры вообще некорректно работают с различными фазами.

Прерывание события

Последнее, о чем поговорим, — это о предотвращении распространения события. У события не обязательно должна быть полноценная жизнь, в которой оно начинается и заканчивается в корне. Бывает, что лучше не давать ему счастливо дожить до старости.

Чтобы прекратить существование события, можно использовать метод stopPropagation в объекте Event:

function handleClick(e) {

e. stopPropagation();

// что-нибудь делает

}

Метод stopPropagation прекращает движение события по фазам. Обратившись к предыдущему примеру, давайте предположим, что вы прослушиваете событие click в элементе three_a и хотите помешать этому событию распространиться. В этом случае код будет выглядеть так: