Javascript интерфейс event
Содержание:
- Опция «passive» для обработчика
- Определение и применение
- Объект события и метод preventDefault
- Неотменяемые события
- Как отменить стандартные действия браузера
- Пример использования
- event.defaultPrevented
- Событие onclick javaScript и три способа обработки событий
- Методы интерфейса
- addEventListener
- Описание интерфейса
- Погружение
- Итого
- Итого
- Итого
Опция «passive» для обработчика
Необязательная опция для сигнализирует браузеру, что обработчик не собирается выполнять .
Почему это может быть полезно?
Есть некоторые события, как на мобильных устройствах (когда пользователь перемещает палец по экрану), которое по умолчанию начинает прокрутку, но мы можем отменить это действие, используя в обработчике.
Поэтому, когда браузер обнаружит такое событие, он должен для начала запустить все обработчики и после, если не вызывается нигде, он может начать прокрутку. Это может вызвать ненужные задержки в пользовательском интерфейсе.
Опция сообщает браузеру, что обработчик не собирается отменять прокрутку. Тогда браузер начинает её немедленно, обеспечивая максимально плавный интерфейс, параллельно обрабатывая событие.
Для некоторых браузеров (Firefox, Chrome) опция по умолчанию включена в для таких событий, как и .
Определение и применение
JavaScript метод dispatchEvent() объекта EventTarget позволяет отправить искусственно созданное событие элементу, синхронно вызывая затронутые прослушиватели событий в соответствующем порядке. Искусственные события всегда имеют значение false в свойстве isTrusted объекта Event.
Обращаю Ваше внимание на то, что события, отправляемые вручную при использовании метода dispatchEvent() используют при этом обычные правила обработки событий (включая стадию захвата и всплытия). Метод dispatchEvent() возвращает логическое значение false, если событие отменяется и по крайней мере один из обработчиков событий, обработавших это событие вызвал метод preventDefault(), в противном случае возвращается логическое значение true
Метод dispatchEvent() возвращает логическое значение false, если событие отменяется и по крайней мере один из обработчиков событий, обработавших это событие вызвал метод preventDefault(), в противном случае возвращается логическое значение true.
В отличие от нативных событий, которые запускаются DOM и вызывают обработчики событий асинхронно через цикл обработки событий, dispatchEvent() вызывает обработчики событий синхронно. Все применимые обработчики событий будут выполняться и возвращаться до продолжения кода после вызова dispatchEvent(), он является последним шагом процесса create-init-dispatch, который используется для отправки событий в модель событий реализации. Событие может быть создано с помощью конструктора событий:
const event = new Event( typeArg ); // тип события const event = new Event( typeArg, eventInit ); // тип события и настройки события typeArg - String eventInit - Object
Значение параметров:
Параметр | Описание |
---|---|
typeArg | Строковое значение, представляющее тип события (значение чувствительно к регистру). Обязательный параметр. |
eventInit | Это словарь EventInit, имеющий следующие поля (является необязательным параметром):
|
Объект события и метод preventDefault
Событие — это какое-то действие, произошедшее на странице. Например, клик,
нажатие кнопки, движение мыши, отправка формы и так далее. Когда срабатывает
событие, браузер создаёт объект события . Этот объект содержит всю информацию о событии. У него есть свои свойства
и методы, с помощью которых можно эту информацию получить и использовать. Один
из методов как раз позволяет отменить действие браузера по умолчанию —
.
можно передать в функцию-обработчик события и в ней указать
инструкции, которые должны быть выполнены, когда оно сработает. При передаче
объекта события в обработчик обычно используется сокращённое написание — .
Пример: когда ссылка — не ссылка
Ранее мы уже говорили о попапе, который должен появляться при клике на ссылку —
давайте разберём этот кейс на практике. Так будет выглядеть разметка в
упрощённом виде:
Мы хотим при клике на ссылку добавлять элементу с классом
класс . Он сделает попап видимым, поменяв значение свойства с
на . Напишем логику добавления этого класса с помощью JavaScript:
Если мы уберём строку , вместо попапа откроется отдельная страница , адрес которой прописан в атрибуте у ссылки. Такая страница нужна, потому что мы хотим, чтобы вся функциональность сайта была доступна, если скрипт по какой-то причине не будет загружен. Именно поэтому мы изначально реализовали кнопку с помощью тега , а не . Но у нас с JavaScript всё в порядке, поэтому вместо отдельной страницы мы открыли попап, отменив действие браузера по умолчанию.
Пример: проверка формы перед отправкой
Разберём следующий кейс — отправку формы при нажатии на кнопку . Допустим, мы хотим перед отправкой проверять введённые данные, потому что в поле ввода обязательно должно быть значение и никакое другое. Разметка формы:
При нажатии на кнопку «Готово» сработает событие отправки формы , и форма отправится вне зависимости от корректности введённого значения, поэтому мы должны перехватить отправку.
Здесь мы не дали отправить форму при неверно введённом значении. Но если всё в порядке, условие не выполнится, и форма будет отправлена как обычно.
Неотменяемые события
Не для всех событий можно отменить действие по умолчанию. Например, событие прокручивания страницы проигнорирует попытки отменить его. Чтобы узнать, можно отменить действие по умолчанию или нет, нужно обратиться к свойству объекта . Оно будет равно , если событие можно отменить, и — в обратном случае.
В статье мы разобрали базовые примеры, когда может понадобиться отмена действия браузера по умолчанию. В реальной разработке вы будете сталкиваться с такой необходимостью довольно часто — при сложной валидации форм, предотвращении ввода пользователем неверных символов, создании кастомного меню вместо стандартного (при клике правой кнопкой мыши) и так далее.
Как отменить стандартные действия браузера
Некоторые элементы (объекты) HTML страницы, имеют стандартные действия, когда с ними взаимодействует пользователь. Например, при нажатии на ссылку браузер осуществляет стандартное действие — это переход на страницу, указанную в атрибуте . Иногда возникают ситуации, когда стандартные действия, которые выполняет браузер необходимо отменить.
Для отмены стандартного действия, который выполняет браузер, необходимо использовать метод объекта .
Синтаксис:
element.addEventListener("click", function(event) { ... event.preventDefault(); }, false);
Например, отменим стандартное действие для элемента , имеющего :
<a id="myAnchor" href="https://www.yandex.ru/">Перейти на сайт Яндекс</a> <script> var myAnchor = document.getElementById("myAnchor"); myAnchor.addEventListener("click", function(event) { console.log("Мы отменили стандартное действие браузера"); event.preventDefault(); }, false); </script>
Если вы подписались на событие через JavaScript с помощью свойства объекта , т.е. способом, не рекомендованным стандартом (). То для отмены стандартного действия кроме также можно ещё использовать .
Предупреждение: Данный способ () не будет работать, если обработчик назначен через метод .
Синтаксис:
element.onclick = function(event) { //... return false; }
Изменим вышеприведённый пример, выполнив подписку на событие «» через свойство DOM-элемента . Для прерывания выполнения действия будем использовать инструкцию :
<a id="myAnchor" href="https://www.yandex.ru/"> Перейти на сайт Яндекс </a> <script> var myAnchor = document.getElementById("myAnchor"); myAnchor.onclick = function() { console.log("Мы отменили стандартное действие браузера"); //возвращаем false, тем самым отменяем стандартное действие браузера, //т.е. прерываем дальнейшее выполнение действия return false; }; </script>
Возможность отменять стандартные действия браузера очень часто применяются перед отправкой формы на сервер. Она используется для того чтобы проверить правильность заполнения формы с помощью скриптов JavaScript.
Пример использования
Создание искусственного события
<!DOCTYPE html> <html> <head> <title>Использование JavaScript метода dispatchEvent()</title> </head> <body> <button onclick = "dispatch()">Dispatch (click)</button> <button onclick = "dispatch2()">Dispatch (click with no bubble)</button> <p>Click me</p> <script> const p = document.querySelector("p"), // выбираем первый элемент p в документе myFunc = function(e) { console.log("click", "bubbles: " + e.bubbles); // выводим в консоль текстовую информацию и значение свойства bubbles объекта Event }; p.addEventListener("click", myFunc, false ); // устанавливаем для элемента обработчик события нажатия левой кнопки мыши на элементе (стадия всплытия) p.addEventListener("click", myFunc, true ); // устанавливаем для элемента обработчик события нажатия левой кнопки мыши на элементе (стадия перехвата) const dispatch = function() { const event = new Event("click", {bubbles: false}); // создаем объект события и указываем, что событие не является всплывающим внутри DOM p.dispatchEvent( event ); // отправляем искусственно созданное событие целевому элементу }; const dispatch2 = function() { const event = new Event("click", {bubbles: true}); // создаем объект события и указываем, что событие является всплывающим внутри DOM p.dispatchEvent( event ); // отправляем искусственно созданное событие целевому элементу }; </script> </body> </html>
В этом примере мы разместили элемент <p>), с помощью метода querySelector() мы выбрали его и инициализировали переменную этим значением.
С помощью метода addEventListener() устанавливаем для элемента <p> функцию обработчик события «click» (нажатие левой кнопкой мыши на элементе) как для фазы всплытия (bubbling phase), так и для фазы перехвата (capture phase). При срабатывании события «click» на этом элементе будет вызываться функция myFunc, которая будет выводить в консоль текстовую информацию и значение свойства bubbles объекта Event.
Кроме того, мы разместили в документе две кнопки (элемент <button>), которым с помощью атрибута событий onclick назначали функции, которые срабатывают при нажатии.
При нажатии на первую кнопку срабатывает функция, которая создает объект события и указывает, что событие не является всплывающим внутри DOM, после этого с использованием метода dispatchEvent() отправляет искусственно созданное событие целевому элементу <p>, в результате чего обработчик события «click» этого элемента будет вызван два раза (для стадии перехвата и всплытия).
При нажатии на вторую кнопку срабатывает аналогичная функция, которая создает объект события и указывает, что событие является всплывающим внутри DOM, после этого с использованием метода dispatchEvent() отправляет искусственно созданное событие целевому элементу <p>, в результате чего обработчик события «click» этого элемента так же будет вызван два раза (для стадии перехвата и всплытия).
Результат нашего примера:
Пример использования JavaScript метода dispatchEvent()
Передача пользовательских данных
Вы можете не только создавать искусственные события, но и добавлять пользовательские данные в объект события, для этого существует интерфейс CustomEvent, а свойство detail можно использовать для передачи пользовательских данных.
// создаем новое событие типа "myEvent" и инициализируем переменную этим значением const myEvent = new CustomEvent("myEvent", { detail: someData } const myEvent2 = new CustomEvent("myEvent", { detail: {method: () => console.log("hello "), method2: () => console.log("hello2 ")} } // инициируем искусственно созданные события document.dispatchEvent(myEvent); document.dispatchEvent(myEvent2);
Вызов встроенных событий
Обращаю Ваше внимание на то, что вы можете создавать не только пользовательские события, но и встроенные события — FocusEvent, MouseEvent, WheelEvent, KeyboardEvent и тому подобное, например:
const myEvent = new MouseEvent("click", { view: window, bubbles: true, cancelable: true }); document.dispatchEvent(myEvent);
JavaScript EventTarget
event.defaultPrevented
Свойство установлено в , если действие по умолчанию было предотвращено, и , если нет.
Рассмотрим практическое применение этого свойства для улучшения архитектуры.
Помните, в главе Всплытие и погружение мы говорили о и упоминали, что останавливать «всплытие» – плохо?
Иногда вместо этого мы можем использовать , чтобы просигналить другим обработчикам, что событие обработано.
Давайте посмотрим практический пример.
По умолчанию браузер при событии (клик правой кнопкой мыши) показывает контекстное меню со стандартными опциями. Мы можем отменить событие по умолчанию и показать своё меню, как здесь:
Теперь в дополнение к этому контекстному меню реализуем контекстное меню для всего документа.
При правом клике должно показываться ближайшее контекстное меню.
Проблема заключается в том, что когда мы кликаем по элементу , то мы получаем два меню: контекстное меню для кнопки и (событие всплывает вверх) контекстное меню для документа.
Как это поправить? Одно из решений – это подумать: «Когда мы обрабатываем правый клик в обработчике на кнопке, остановим всплытие», и вызвать :
Теперь контекстное меню для кнопки работает как задумано. Но цена слишком высока. Мы навсегда запретили доступ к информации о правых кликах для любого внешнего кода, включая счётчики, которые могли бы собирать статистику, и т.п. Это слегка неразумно.
Альтернативным решением было бы проверить в обработчике , было ли отменено действие по умолчанию? Если да, тогда событие было обработано, и нам не нужно на него реагировать.
Сейчас всё работает правильно. Если у нас есть вложенные элементы и каждый из них имеет контекстное меню, то код также будет работать. Просто убедитесь, что проверяете в каждом обработчике .
event.stopPropagation() и event.preventDefault()
Как мы можем видеть, и (также известный как ) – это две разные функции. Они никак не связаны друг с другом.
Архитектура вложенных контекстных меню
Есть также несколько альтернативных путей, чтобы реализовать вложенные контекстные меню. Одним из них является единый глобальный объект с обработчиком и методами, позволяющими хранить в нём другие обработчики.
Объект будет перехватывать любой клик правой кнопкой мыши, просматривать сохранённые обработчики и запускать соответствующий.
Но при этом каждый фрагмент кода, которому требуется контекстное меню, должен знать об этом объекте и использовать его вместо собственного обработчика .
Событие onclick javaScript и три способа обработки событий
Событие происходит во время одинарного щелчка кнопкой мыши. Обычно для события назначается обработчик, то есть функция, которая сработает, как только событие произошло. Обработать событие, т.е. отреагировать на него посредством скрипта, можно тремя способами. Рассмотрим их:
Пример: По щелчку на кнопке вывести диалоговое окно с сообщением «Ура!»
- Через свойство объекта с использованием пользовательской функции:
Скрипт:
function message() { alert("Ура!"); } |
html-код:
<body> <form> <input type="button" name= "myButton" onclick="message()" value="Щелкни!"> <form> |
В данном примере в html-коде мы видим кнопку. У кнопки присутствует атрибут («по щелчку»), в значении которого стоит вызов функции с названием . Это пользовательская функция, описанная выше в скрипте. В самой функции выводится диалоговое окно, что и задано согласно заданию.
Скрипт при такой обработке события обычно находится в области документа
Через атрибут тега:
<body> <form name="myForm"> <input type="button" name="myButton" value="Щелкни!" onclick="javascript: alert('Ура!')"> <form> |
Это упрощенный вариант обработки события, он подходит только для небольшого кода, когда необходимо выполнить один-два оператора. Иначе код будет плохочитаемым.
В качестве атрибута кнопки указывается («по щелчку»), а в качестве значения пишется скрипт из операторов с указанием на каком языке он написан (). В нашем случае оператор для вывода модального окна со словом «Ура!»
Через регистрацию функции-обработчика в качестве свойства элемента:
html-код:
<form name="myForm"> <input type="button" value="Щелкни!" id="myButton"> <form> |
Скрипт:
document.myForm.myButton.onclick = message; function message() { alert('Ура!'); } |
В html-коде здесь присутствует кнопка с атрибутом , который необходим для обращения к кнопке через скрипт.
В скрипте, который обязательно находится ниже дерева элементов (можно перед закрытием тега ), находится обращение к кнопке (), для которой назначается обработчик события со значением ссылки на функцию. Обращение к кнопке может быть организовано через атрибут ()
Скобки после названия функции не ставятся. В данном случае это именно ссылка на функцию, иначе, при использовании скобок, функция была бы вызвана, а не назначена в качестве обработчика событий.
Именно такой способ обработки событий максимально приближен к тому, который происходит, например, в ОС windows.
Как лучше выводить результаты примеров?
Важно: При вызове после окончания загрузки страницы (при обработке событий onclick, oninput, …), страница перезапишется, поэтому вызывать этот метод не рекомендуется. Для примеров лучше использовать метод .
добавляет html во время построения DOM
блокируют выполнение JS, пока пользователь не нажмёт OK
Рассмотрим все простые способы вывода отладочной информации:
-
alert('str'); // показывает окошко
-
document.write('htmlstr'); // пишет на страницу
-
document.innerHTML += 'htmlstr'; // добавляет на страницу
-
console.log('str'); // выводит в консоль браузерах
Задание Js8_5. Выполните задание по инструкции:
- Создайте веб-страницу и расположите в ней тег с изображением грустного смайлика.
- Щелчок на изображении () вызывает заданный метод (пользовательская функция):
<img id="smileImg" src="smile1.jpg" onclick="sayHello()" > |
В скрипте опишите метод (функция ), который «спрашивает», как зовут пользователя, а затем приветствует его по имени, и меняет изображение на улыбающийся смайлик (свойство тега ):
function sayHello() { var userName=prompt("Как вас зовут?"); if(userName){ alert(...); document.getElementById("smileImg"). ...=...; } } |
=>>
Методы интерфейса
Метод | Описание | Chrome | Firefox | Opera | Safari | IExplorer | Edge |
---|---|---|---|---|---|---|---|
composedPath() | Возвращает путь события, представляющий собой массив объектов, на которых будут вызваны обработчики событий. | 53.0 | 52.0 | 40.0 | 10.0 | Нет | Нет |
preventDefault() | Если этот метод вызывается, то действие события по умолчанию не будет срабатывать (отменяет действие события по умолчанию). Событие продолжает распространяться как обычно, только с тем исключением, что событие ничего не делает. | Да | Да | Да | Да | 9.0 | Да |
stopImmediatePropagation() | Прекращает дальнейшую передачу текущего события (предотвращает всплытие по дереву DOM) и останавливает цепочку вызова событий для текущего элемента. | Да | Да | Да | Да | 9.0 | Да |
stopPropagation() | Прекращает дальнейшую передачу текущего события (предотвращает всплытие по дереву DOM). | Да | Да | Да | Да | 9.0 | Да |
addEventListener
Фундаментальный недостаток описанных выше способов назначения обработчика –- невозможность повесить несколько обработчиков на одно событие.
Например, одна часть кода хочет при клике на кнопку делать её подсвеченной, а другая – выдавать сообщение.
Мы хотим назначить два обработчика для этого. Но новое DOM-свойство перезапишет предыдущее:
Разработчики стандартов достаточно давно это поняли и предложили альтернативный способ назначения обработчиков при помощи специальных методов и . Они свободны от указанного недостатка.
Синтаксис добавления обработчика:
- Имя события, например .
- Ссылка на функцию-обработчик.
- Дополнительный объект со свойствами:
- : если , тогда обработчик будет автоматически удалён после выполнения.
- : фаза, на которой должен сработать обработчик, подробнее об этом будет рассказано в главе Всплытие и погружение. Так исторически сложилось, что может быть , это то же самое, что .
- : если , то указывает, что обработчик никогда не вызовет , подробнее об этом будет рассказано в главе Действия браузера по умолчанию.
Для удаления обработчика следует использовать :
Удаление требует именно ту же функцию
Для удаления нужно передать именно ту функцию-обработчик которая была назначена.
Вот так не сработает:
Обработчик не будет удалён, т.к
в передана не та же функция, а другая, с одинаковым кодом, но это не важно
Вот так правильно:
Обратим внимание – если функцию обработчик не сохранить где-либо, мы не сможем её удалить. Нет метода, который позволяет получить из элемента обработчики событий, назначенные через
Метод позволяет добавлять несколько обработчиков на одно событие одного элемента, например:
Как видно из примера выше, можно одновременно назначать обработчики и через DOM-свойство и через . Однако, во избежание путаницы, рекомендуется выбрать один способ.
Обработчики некоторых событий можно назначать только через
Существуют события, которые нельзя назначить через DOM-свойство, но можно через .
Например, таково событие , которое срабатывает, когда завершена загрузка и построение DOM документа.
Так что более универсален. Хотя заметим, что таких событий меньшинство, это скорее исключение, чем правило.
Описание интерфейса
Интерфейс Event представляет собой любое событие, которое происходит в объектной модели документа (DOM). Некоторые события создаются непосредственно пользователем (например, события мыши, или клавиатуры), а другие генерируются программным интерфейсом приложения (API), например, такие события как завершение анимации, или приостановка видео.
Когда вызывается какой-либо обработчик события, то в этом случае ему передается объект Event, свойства этого объекта содержат дополнительную информацию о событии, например, такую как тип события и объект, который отправил событие. С помощью методов объекта Event можно управлять распространением события по дереву DOM.
Погружение
Существует ещё одна фаза из жизненного цикла события – «погружение» (иногда её называют «перехват»). Она очень редко используется в реальном коде, однако тоже может быть полезной.
Стандарт DOM Events описывает 3 фазы прохода события:
- Фаза погружения (capturing phase) – событие сначала идёт сверху вниз.
- Фаза цели (target phase) – событие достигло целевого(исходного) элемента.
- Фаза всплытия (bubbling stage) – событие начинает всплывать.
Картинка из спецификации демонстрирует, как это работает при клике по ячейке , расположенной внутри таблицы:
То есть при клике на событие путешествует по цепочке родителей сначала вниз к элементу (погружается), затем оно достигает целевой элемент (фаза цели), а потом идёт наверх (всплытие), вызывая по пути обработчики.
Ранее мы говорили только о всплытии, потому что другие стадии, как правило, не используются и проходят незаметно для нас.
Обработчики, добавленные через -свойство или через HTML-атрибуты, или через с двумя аргументами, ничего не знают о фазе погружения, а работают только на 2-ой и 3-ей фазах.
Чтобы поймать событие на стадии погружения, нужно использовать третий аргумент вот так:
Существуют два варианта значений опции :
- Если аргумент (по умолчанию), то событие будет поймано при всплытии.
- Если аргумент , то событие будет перехвачено при погружении.
Обратите внимание, что хоть и формально существует 3 фазы, 2-ую фазу («фазу цели»: событие достигло элемента) нельзя обработать отдельно, при её достижении вызываются все обработчики: и на всплытие, и на погружение. Давайте посмотрим и всплытие и погружение в действии:
Давайте посмотрим и всплытие и погружение в действии:
Здесь обработчики навешиваются на каждый элемент в документе, чтобы увидеть в каком порядке они вызываются по мере прохода события.
Если вы кликните по , то последовательность следующая:
- → → → (фаза погружения, первый обработчик)
- (фаза цели, срабатывают обработчики, установленные и на погружение и на всплытие, так что выведется два раза)
- → → → (фаза всплытия, второй обработчик)
Существует свойство , содержащее номер фазы, на которой событие было поймано. Но оно используется редко, мы обычно и так знаем об этом в обработчике.
Чтобы убрать обработчик , нужна та же фаза
Если мы добавили обработчик вот так , то мы должны передать то же значение аргумента в , когда снимаем обработчик.
На каждой фазе разные обработчики на одном элементе срабатывают в порядке назначения
Если у нас несколько обработчиков одного события, назначенных на один элемент, в рамках одной фазы, то их порядок срабатывания – тот же, в котором они установлены:
Итого
Алгоритм:
- При наступлении события – элемент, на котором оно произошло, помечается как «целевой» ().
- Далее событие сначала двигается вниз от корня документа к , по пути вызывая обработчики, поставленные через .
- Далее событие двигается от вверх к корню документа, по пути вызывая обработчики, поставленные через и .
Каждый обработчик имеет доступ к свойствам события:
- – самый глубокий элемент, на котором произошло событие.
- (=) – элемент, на котором в данный момент сработал обработчик (до которого «доплыло» событие).
- – на какой фазе он сработал (погружение =1, всплытие = 3).
Любой обработчик может остановить событие вызовом , но делать это не рекомендуется, так как в дальнейшем это событие может понадобиться, иногда для самых неожиданных вещей.
В современной разработке стадия погружения используется очень редко.
Этому есть две причины:
-
Историческая – так как IE лишь с версии 9 в полной мере поддерживает современный стандарт.
-
Разумная – когда происходит событие, то разумно дать возможность первому сработать обработчику на самом элементе, поскольку он наиболее конкретен. Код, который поставил обработчик именно на этот элемент, знает максимум деталей о том, что это за элемент, чем он занимается.
Далее имеет смысл передать обработку события родителю – он тоже понимает, что происходит, но уже менее детально, далее – выше, и так далее, до самого объекта , обработчик на котором реализовывает самую общую функциональность уровня документа.
Итого
Чтобы сгенерировать событие из кода, вначале надо создать объект события.
Базовый конструктор принимает обязательное имя события и – объект с двумя свойствами:
- чтобы событие всплывало.
- если мы хотим, чтобы работал.
Особые конструкторы встроенных событий , и другие принимают специфичные для каждого конкретного типа событий свойства. Например, для событий мыши.
Для пользовательских событий стоит применять конструктор . У него есть дополнительная опция , с помощью которой можно передавать информацию в объекте события. После чего все обработчики смогут получить к ней доступ через .
Несмотря на техническую возможность генерировать встроенные браузерные события типа или , пользоваться ей стоит с большой осторожностью. Весьма часто, когда разработчик хочет сгенерировать встроенное событие – это вызвано «кривой» архитектурой кода
Весьма часто, когда разработчик хочет сгенерировать встроенное событие – это вызвано «кривой» архитектурой кода.
Как правило, генерация встроенных событий полезна в следующих случаях:
- Либо как явный и грубый хак, чтобы заставить работать сторонние библиотеки, в которых не предусмотрены другие средства взаимодействия.
- Либо для автоматического тестирования, чтобы скриптом «нажать на кнопку» и посмотреть, произошло ли нужное действие.
Пользовательские события со своими именами часто создают для улучшения архитектуры, чтобы сообщить о том, что происходит внутри наших меню, слайдеров, каруселей и т.д.
Итого
При наступлении события – самый глубоко вложенный элемент, на котором оно произошло, помечается как «целевой» ().
- Затем событие сначала двигается вниз от корня документа к , по пути вызывая обработчики, поставленные через , где – это сокращение для .
- Далее обработчики вызываются на целевом элементе.
- Далее событие двигается от вверх к корню документа, по пути вызывая обработчики, поставленные через и без третьего аргумента или с третьим аргументом равным .
Каждый обработчик имеет доступ к свойствам события :
- – самый глубокий элемент, на котором произошло событие.
- (=) – элемент, на котором в данный момент сработал обработчик (тот, на котором «висит» конкретный обработчик)
- – на какой фазе он сработал (погружение=1, фаза цели=2, всплытие=3).
Любой обработчик может остановить событие вызовом , но делать это не рекомендуется, так как в дальнейшем это событие может понадобиться, иногда для самых неожиданных вещей.
В современной разработке стадия погружения используется очень редко, обычно события обрабатываются во время всплытия. И в этом есть логика.
В реальном мире, когда происходит чрезвычайная ситуация, местные службы реагируют первыми. Они знают лучше всех местность, в которой это произошло, и другие детали. Вышестоящие инстанции подключаются уже после этого и при необходимости.
Тоже самое справедливо для обработчиков событий. Код, который «навесил» обработчик на конкретный элемент, знает максимум деталей об элементе и его предназначении. Например, обработчик на определённом скорее всего подходит только для этого конкретного , он знает все о нём, поэтому он должен отработать первым. Далее имеет смысл передать обработку события родителю – он тоже понимает, что происходит, но уже менее детально, далее – выше, и так далее, до самого объекта , обработчик на котором реализовывает самую общую функциональность уровня документа.
Всплытие и погружение являются основой для «делегирования событий» – очень мощного приёма обработки событий. Его мы изучим в следующей главе.