Эта обзорная статья о событиях и их обработчиках описывает шаблон проектирования кода, который используется для реагирования на события, возникающие, когда браузер получает доступ к web-странице, и содержит подборку типов подобных событий, которые современные брауезеры могут обрабатывать.
События и их обработчики представляют собой основную технику в JavaScript для реагирования на события, возникающие, когда браузер получает доступ к web-странице, включая события о подготовке страницы к отображению, взаимодействии с ее содержимым, в зависимости от устройства, на котором браузер был запущен, и многие другие случаи, такие как воспроизведение потоковой медиа-информации или расчет времени анимации.
События и обработчики событий заняли центральное место в web-программировании с добавлением языка в браузеры, сопровождая смену архитектуры рендеринга от перехвата и загрузки страницы к управлению с помощью событий, основанном на перекомпановке (reflow). Сначала браузер ожидает, пока он получит все ресурсы, связанные со страницей, чтобы проанализировать, обработать, отрисовать и предоставить страницу пользователю. Отрисованная страница остается неизменной, пока браузер не запросит новую. С изменением в подходе к рендерингу динамической страницы, браузер непрерывно зацикливается между обработкой, отрисовкой, представлением содержимого и ожиданием некоторого нового триггера события. Триггеры событий включают, например, завершение загрузки ресурса по сети, скачивание изображений, которые теперь могут быть отрисованы на экране, завершение браузером анализа ресурса, обработку HTML-содержимого страницы, взаимодействие пользователя с содержимым страницы, нажатия кнопок. Дуглас Крокфорд хорошо объясняет это изменение в нескольких лекциях, особенно своей речи "Неудобные API: Теория DOM", которая описывает изменения в потоке изначального потока браузера от управляемого событиями браузера.
Второй подход изменяет последние шаги, переходя от просторого потока к бесконечному циклу, где ожидание и обработка возникновения новых событий следует за отрисовкой. Введение динамического подхода позволяет странице быть частично отрендериной, даже когда браузер еще не закончил извлечение всех ресурсов; это так же разрешено для действий, управляемыми событиями, которые JavaScript использует. (Речь доступна на нескольких ресурсах, включая этот.) На данный момент, все среды исполнения JavaScript используют события и их обработчики.
Шаблон проектирования событий
Система событий, по своей сути, простой программный шаблон проектирования. Он начинается с соглашения о виде события и:
- имени-строки, используемой для собыйтия,
- типа структуры данных, используемых для представления ключевых свойств события,
- объекта JavaScript, который будет 'вызывать' это событие.
Шаблон реализуется с помощью:
- определение JavaScript-функции, которая принимает в качестве аргумента структуру данных, которая была согласована ранее, и
- регистрации функции с помощью имени-строки через объект, который будет вызывать событие.
Функция считается "слушателем" или "обработчиком", где оба именами взаимнозаменяемы. Этому шаблону можно легко следовать с использованием полностью пользовательского кода, как объяснено в статье о пользовательских событиях. Шаблон так же используется современными web-браузерами, определяющими множество событий, которые вызываются в ответ на пользовательский ввод или активность браузера.
Современные браузеры следуют событийному шаблону, используя стандартизированный подход. В качестве структуры данных для свойств события они применяют объект, полученный от объекта EventPrototype
. Для регистратрации функции, которая будет обрабатывать эту структуру даных, используется метод, называемый addEventListener
, который ожидает в качестве аргумента имя-строку, соответствующую типу события, и функцию-обработчика. В итоге, браузеры определяют огромное число объектов источников событий и широкое разнообразие типов событий, сформированных объектами.
Пример обработчика события кнопки
К примеру, браузерный элемент button
предназначен для вызова события с именем 'click'
в ответ на нажатие кнопки мыши или прикосновене пальца к чувствительной части экрана. В HTML мы можем определить button
как:
<button id="buttonOne">Click here to emit a 'click' event</button>
и, в коде JavaScript, мы можем сначала определить функцию для прослушивания этого события 'click'
:
var example_click_handler = function (ev){
var objKind = (ev instanceof Event) ? "EventPrototype" : "ObjectPrototype";
alert("We got a click event at " + ev.timeStamp + " with an argument object derived from: " + objKind );
};
и затем зарегестрировать свою функцию с помощью объекта Button
или со стороны скрипта, используя представление DOM (Document Object Model) на HTML-странице:
var buttonDOMElement = document.querySelector('#buttonOne');
buttonDOMElement.addEventListener('click', example_click_handler);
или на самой HTML-странице, добавив функцию как значение атрибута 'onclick'
, хотя этот вариант обычно используется на очень простых web-страницах.
Этот код полагается на соглашение о том, что существует некоторый вид события, называемый 'click'
, который вызовет все функции-слушатели (или 'обработчи') с объектом-аргументом Event
(на данный момент, в этом случае производный от объекта MouseEvent
) и будет запущен после манипуляций пользователя с элементами button
на HTML-странице. Код не имеет видимого воздействия, пока пользователь не использует кнопки, наводит указатель мыши на элемент HTML и нажимает на левую кнопку или устанавливает палец или стилус на некоторое место на экране, выше кнопки; когда это произойдет, buttonDOMElement
объекта JavaScript вызовет функцию example_click_handler
с объектом Event
в качестве аргумента. Функция, в свою очередь, исполнит любые действия, описанные программистом, в данном случае отрыв диалоговое окно HTML. Заметим, что обработчик имеет доступ к объекту ev
, так как тот передается в качестве аргумента; объект содержит информацию о событие, в частности время его возникновения.
Во втором варианте, интегрирован в web-страницу намного более современный JavaScript обернут в событийный вызов функции, чтобы убедиться, что код будет выполнен только тогда, когда HTML будет обработан и доступен для изменения или декорирования. Например, код может быть объявлен так:
var funcInit = function(){
// user code goes here and can safely address all the HTML elements from the page
// since the document has successfully been 'loaded'
}
document.addEventListener('DOMContentLoaded', funcInit);
так что этот код будет вызван только после того, как объект document
вызовет событие 'DOMContentLoaded'
, потому что HTML был проанализирован и были созданы объекты Javasript, представляющие каждый узел HTML-документа. Заметим, что в этом примере, код даже не передает аргумент события в функцию, потому что тому никогда не понадобится использовать данные, описанные в нем; скорее, код всего лишь нужно подождать, пока не случится событие.
Шаблон легко изучить и внедрить. Сложность с событиями возникает из-за необходимости изучить большое разнообразие событий, которые представлены в современных web-браузерах. Так же есть некоторая сложность в понимании, как писать обработчики, так как данный код работает ассинхронно и потенциально может быть вызван несколько раз подряд, но в немного другой ситуации.
Важные события
Web-браузеры определяют большое число событий, поэтому не практично описывать их все. Event Reference призван содержать список стандартных событий, используемых в современных браузерах.
В общем случае, события различного вида выделяют, основываясь на объекте, который вызывает данное событие, включая:
- объект
window
, на случай изменения размера браузера, - объект
window.screen
, на случай изменения положения устройства, - объект
document
, включая загрузку, модификацию, пользовательское взаимодействие и разгрузку страницы, - объект в DOM (объектная модель документа) дереве, включая пользовательское взаимодействие или изменения,
- объект
XMLHttpRequest
, используемый для запросов сети, и - медиа-объекты, такие как
audio
иvideo
, когда медиа-потоковые плееры изменяют состояние.
хотя этот список на данный момент неполный.
Некоторые события, которые стоит отметить:
Заметка: Этот список событий будет нуждаться в доработке, чтобы соответствовать действительности; эта работа ожидает некоторой глобальной реорганизации в документе. Так же нужно найти хорошее объяснение событий, включая события во время загрузки страницы, таких, как частично описаных в этой статье или этом вопросе на Stack Overflow.
- глобальный объект
window
вызывает событие, называемое'load'
, когда страница закончила рендеринг, подразумевая, что все ресурсы были скачаны и применены, так что скрипт был выполнен и изображения отображены, - глобальный объект
window
вызывает событие, называемое'resize'
, когда высота или ширина окна браузера была измененеа пользователем, - объект DOM
document
, представляющий HTML-документ, вызывает событие, называемое'DOMContentLoaded'
, когда документ закончил загрузку, - объект узла DOM, такой как
div
илиbutton
, вызывающий событие, называемое'click'
, когда пользователь нажимает кнопку мыши, пока ее указатель находится поверх узла DOM на HTML-странице.
Иерархия объекта событий
Web-браузер определяет множество событий различного вида. Каждое описание включает, как структуру данных, передающуюся в обработчика, объект, который наследуется от объекта EventPrototype
.
Частичная диаграма иерархии класса объекта событий:
Заметка: Эта диаграма неполная.
Web API Документация содержит страницу, описывающую объект событий, который так же включает известные события DOM, подклассы объекта Event
.
Документации
Три ресурса на MDN (Mozilla Developer Network) частично полезные для программистов, желащих работать с событиями:
- Гайд по событиям, который является частью Web Developers' Guide,
- Event Reference,
- Web API Документация по объекту
Event
.