События JavaScript
В этой главе:
Динамические страницы основываются на событиях. События возникают при взаимодействии пользователя с документом, а также при изменении его состояния. Например, когда пользователь перемещает указатель мышки, нажимает на кнопку, щелкает по ссылке, или вводит в форму текст, происходит соответствующие событие. Завершение загрузки документа, или его части (например, картинки или иного объекта), а также смена фокуса ввода, тоже генерируют событие.
Современная модель событий (Event Model) состоит из двух составляющих. Прежде всего, это новая модель, подразумевающая единую модель обработки событий, основанную на иерархической структуре документа. Она поддерживает назначение обработчиков событий через сценарии и предоставляет стандартный набор для всех элементов управления документом и его изменений. Другая сторона – это подмножество системы событий, заимствованная из DOM уровня 0, т.е., фактически, из Netscape 3. Таким образом, достигается совместимость «сверху вниз».
В целом, модель современная событий динамических страниц основывается на всплывании событий и действиях по умолчанию. При этом следует учитывать, что всплывание поддерживается всеми рассматриваемыми браузерами, кроме Netscape 4.
Типы событий и их вызов
Начиная с HTML 4.0, все элементы документа имеют атрибуты для поддержки событий, вызываемых клавиатурой и мышкой. Это onclick, ondblclick, onmousedown, onmouseup, onmouseover, onmousemove, onmouseout, onkeypress, onkeydown и onkeyup, их описание приводится в конце второй части этой книги (см. таблицу 2.43). Кроме того, формы поддерживают атрибуты onsubmit и onreset, а их элементы для ввода текста так же onchange и onselect. Наконец, ссылки и элементы форм поддерживают атрибуты onblur и onfocus.
Для назначения обработчика события любому элементу достаточно указать в качестве значения соответствующего атрибута элемента либо функцию JavaScript, либо непосредственно код сценария для выполнения:
<p onclick="alert('Ну и чего?');">Щелкни тут!</p>
<p onmouseover="MouseFunc();">Проведи мышкой!</p>
Примеры того, как работают подобные обработчики событий, можно посмотреть в файле Part_4\Events\simple.html.
Существует и еще один способ связывания событий – явный вызов. Для этого создается функция JavaScript, которая будет обрабатывать событие, а затем присваивается элементу:
function MyHandler() {
alert('Хватит кликать!');
}
document.links[0].onclick=MyHandler;
Здесь первой ссылке документа присваивается обработчик события «MyHandler» для обработки щелчков мышью. Обратите внимание на то, что в строке присвоения обработчика указывается именно имя функции – MyHandler, поскольку, если добавить скобки – myHandler(), – то функция будет не присвоена обработчику, а просто вызвана.
В тех случаях, когда требуется присвоить обработчик события к произвольному элементу документа, то это делается точно так же:
document.getElementById("MyElement").onkeypress=MyHandler;
В данном случае мы назначили обработчиком события onkeypress (нажатие клавиши) функцию «MyHandler» для элемента с идентификатором «MyElement».
ПРИМЕЧАНИЕ
Microsoft, выпустив 4-ю версию Internet Explorer, предложила еще один способ назначения обработчиков событий – при помощи специальных атрибутов для тега SCRIPT – FOR и EVENT. Однако они не были утверждены ни в HTML 4.0/4.01 ни в XHTML. Пример с использованием этих атрибутов см. в файле ms_way.html.
Наконец, в том случае, когда требуется назначить обработчик события для всего документа, достаточно написать выражение типа:
document.ИмяСобытия=Обработчик
Самое замечательное в этом методе то, что он будет работать со всеми браузерами, включая даже "антикварный" Netscape 3.
В таблице 4.19 перечислены все события, которые могут инициировать различные элементы HTML-документов. Вы можете сопоставить ее с таблицей 2.43, чтобы определиться с поддержкой того или иного события конкретными элементами.
Событие | Обработчик | Когда происходит |
---|---|---|
Abort | onabort | При прекращении загрузки картинки пользователем, например, нажатием «Stop» |
BeforeUnload | onbeforeunload | При запросе на начало выгрузки документа |
Blur | onblur | При удалении фокуса ввода из окна или элемента формы |
Change | onchange | При изменении значения полей ввода формы или элемента SELECT |
Click | onclick | При щелчке по элементу |
Close | onclose | При закрытии окна документа |
Error | onerror | При возникновении ошибки в ходе загрузки изображения или документа |
Focus | onfocus | При получении элементом фокуса ввода |
KeyDown | onkeydown | В момент нажатия на клавишу клавиатуры |
KeyPress | onkeypress | При нажатии на кнопку клавиатуры |
KeyUp | onkeyup | В момент, когда отпущена ранее нажатая клавиша клавиатуры |
Load | onload | При завершении загрузки тела страницы |
MouseDown | onmousedown | При нажатии на кнопку мышки |
MouseMove | onmousemove | При движении указателя мышки |
MouseOut | onmouseout | В момент, когда указатель мышки покидает область объекта |
MouseOver | onmouseover | При перемещении указателя над объектом |
MouseUp | onmouseup | При отпускании кнопки мышки |
Move | onmove | При перемещении окна браузера |
Reset | onreset | При очистке формы (нажатии на кнопку “Reset” формы) |
Resize | onresize | При изменении размеров окна браузера |
Scroll | onscroll | При прокрутке окна документа в браузере |
Select | onselect | При выборе элемента формы для ввода текста |
Submit | onsubmit | При отправке формы |
Unload | onunload | При выгрузке тела документа |
Еще один пример обработки событий в формах и назначения их через сценарий находится в файле formevents.html.
Всплывание событий и действия по умолчанию
Как нам известно, действительные документы XHTML представляют собой строгую иерархическую структуру. Когда в каком-либо элементе возникает событие, оно двигается вверх по иерархии документа – всплывает. Например, если щелкнуть по изображению, которое является ссылкой, то сначала событие произойдет для самого изображения, затем – для ссылки, в которую оно вложено, после чего – в теле документа, и, наконец, в самом документе:
<html>
<body>
<a href="http://www.snkey.net">
<img src="1.gif" alt="Картинка" />
</a>
</body>
</html>
Здесь намеренно поставлены большие отступы, чтобы нагляднее была видна иерархия элементов документа. Если бы всплывания событий не было, то пришлось бы создавать обработчики для каждого элемента отдельно.
Чтобы представить всплывание событий наглядно, можно добавить обработчик события Click для каждого элемента в документе:
<html onclick="alert(this.tagName);>
<body onclick="alert(this.tagName);>
<a href="http://www.snkey.net" onclick="alert(this.tagName);>
<img src="1.gif" alt="Картинка" onclick="alert(this.tagName); />
Тескт ссылки
</a>
</body>
</html>
Если щелкать по разным местам документа, то будут выдаваться сообщения, соответствующие текущему уровню продвижения события по документу. Например, при щелчке по строке «текст ссылки» события произойдут для элементов A, BODY и HTML, а при щелчке по картинке – еще и для IMG. Щелчок же по пустому месту документа над картинкой или на уровне с ней приведет в действие события для BODY и HTML, а ниже – только для HTML.
Данный пример не будет работать в Netscape 4 (за исключением генерации сообщения для ссылки), поскольку его система событий не поддерживает всплывание. Именно поэтому, даже в тех случаях, когда само по себе наличие ссылки не требуется, для возможности отслеживания события (например, чтобы сменить картинку при подведении мышки), требуемый объект обычно вкладывают в контейнер A, а в значении атрибута HREF при этом указывают «#». В то же время, если исключить Netscape 4 (вместе с MSIE 3 и еще более древними программами) из списка поддерживаемых вашими страницами платформ, то необходимость в таком трюке отпадает.
Чтобы отследить всплывание события в более объемном документе, вовсе не обязательно добавлять атрибуты для каждого элемента вручную. Достаточно просто выбрать все элементы документа, воспользовавшись, к примеру, методом getElementsByTagName, после чего назначить им обработчики:
var tags = document.getElementsByTagName("*");
for (var i=0; i<tags.length; i++) {
tags[i].onclick=ShowTag;
}
Здесь сначала все элементы документа заносятся в массив tags (звездочка в качестве параметра означает «все элементы»), после чего всем им последовательно в качестве обработчика события Click назначается функция ShowTag. Для просмотра работы данного примера можно обратиться к файлу bubble.html.
Таким образом, всплывание существенно упрощает назначение обработчиков событий для элементов документа, при этом расширяя возможности взаимодействия между самим документом, сценариями и собственно пользователем.
Кроме назначенных обработчиков событий, существуют действия по умолчанию, т.е. действия, которые браузер выполняет в ответ на событие. Например, действием по умолчанию для нажатия на ссылку, является переход по указанному в ссылке адресу и загрузка новой страницы.
Действие по умолчанию не всегда определяется самим источником события – оно может определяться и его родительским элементом. В приведенном выше примере, когда пользователь нажимает кнопку мыши на изображении, действие по умолчанию определяется элементом A, а не IMG.
Интерфейс event
Интерфейс Event предоставляет доступ к информации о событии и обеспечивает контроль всплывания событий, а так же управляет выполнением действий по умолчанию. Он создается браузером автоматически, в момент возникновения того или иного события, например, нажатия на клавишу клавиатуры или щелчка кнопки мышки.
Реализация модели событий в MSIE и в других браузерах, включая Netscape 4, Mozilla и Opera, несколько различается. Так, для любого события в Internet Explorer объект event предоставляет следующие свойства:
- event.srcElement – указывает на объект, послуживший источником события;
- event.cancelBubble – предоставляет возможность запретить всплывание события. По умолчанию установлен в false, т.е. всплытие разрешено;
- event.returnValue – предоставляет возможность отменить действие по умолчанию для элемента.
Из перечисленных выше свойств Mozilla поддерживает только srcElement и cancelBubble, а Netscape 4 не поддерживает и их, в частности, по причине отсутствия в нем механизма всплытия событий. В то же время для srcElement в Netscape предусмотрен эквивалент – target, обозначающий в точности то же самое. Этот же атрибут поддерживается и всем остальными браузерами, поскольку именно target, а не srcElement пределен стандартным именем этого атрибута в спецификации DOM.
Вообще же в стандарте DOM 2 Events помимо тех свойств, что отличаются от поддерживаемых MSIE только названием, имеется целый ряд иных. Кроме того, браузеры Mozilla и MSIE имеют собственные фирменные расширения. Чтобы разобраться во всем этом разнообразии, обратимся к таблице 4.20.
Свойство | Примечание | Описание |
---|---|---|
altKey | - | Указывает, была ли в момент возникновения события нажата клавиша ALT |
bubbles | Mozilla, Opera 7 | Указывает, может ли данное событие всплывать |
button | Mozilla, MSIE | Возвращает номе нажатой кнопки мышки: 0 – левая, 1- средняя, 2 – правая |
cancelBubble | Нестандартное, Mozilla, MSIE | Определяет, должно ли быть всплывание отменено для данного события |
cancelable | Mozilla, Opera 7 | Указывает, может ли данное событие быть прервано |
charCode | Нестандартное, Mozilla | Указывает на код символа нажатой клавиши |
clientX, clientY | - | Указывают на координаты возникновения события по отношению к видимой части окна браузера |
ctrlKey | - | Указывает, была ли в момент возникновения события нажата клавиша CTRL |
currentTarget | Кроме MSIE | Возвращает ссылку на текущее расположение события |
detail | Mozilla, Opera 7 | Возвращает дополнительные параметры события |
eventPhase | Mozilla, Opera 7 | Указывает на фазу всплытия события |
isChar | Нестандартное, Mozilla | Указывает, является ли источником события нажатие на алфавитно-цифровую клавишу |
keyCode | Нестандартное, Opera, MSIE | Указывает на код символа нажатой клавиши |
layerX, layerY | Нестандартные, Mozilla | Указывают на координаты возникновения события по отношению к текущему позиционированному блоку |
offsetX, offsetY | Нестандартные, MSIE, Opera 7 | Указывают на координаты возникновения события по отношению к текущему позиционированному блоку |
pageX, pageY | Нестандартные, Mozilla, Opera 7 | Указывают на координаты возникновения события по отношению ко всему текущему документу |
relatedTarget | Mozilla, Opera 7 | Указывает на вторичную цель события. Используется совместно с событиями MouseOut и MouseOver |
screenX, screenY | - | Указывают на координаты возникновения события по отношению к экрану монитора |
shiftKey | - | Указывает, была ли в момент возникновения события нажата клавиша SHIFT |
srcElement | Только MSIE | Возвращает ссылку на исходное расположение события |
target | Кроме MSIE | Возвращает ссылку на исходное расположение события |
timeStamp | Mozilla, Opera 7 | Возвращает время в миллисекундах, прошедшее с момента возникновения события |
type | - | Возвращает имя (название) события |
Как видно, некоторые свойства (скажем, charCode и keyCode, или layerX и offcetX), по сути, являются синонимами, но эти различия создают ряд проблем для авторов страниц. Единственный выход – это дублирование фрагментов кода в вариантах для различных программ просмотра, либо назначение значений одних свойств другим.
Еще одно различие состоит в том, что сама информация о событии передается в обработчики по-разному. В MSIE она доступна через объект event внутри тела функции, обрабатывающей событие, в то время как для других браузеров требуется указать переменную, которой будет присвоено состояние события. Таким образом, в MSIE функция, обрабатывающая событие, в простейшем случае может выглядеть примерно так:
function MyHandler() {
alert(event.screenX);
}
А для Firefox и Chrome требуется указать аргумент функции, которому и будут назначены все параметры события:
function MyHandler(MyEvent) {
alert(MyEvent.screenX);
}
Чтобы разрешить эту проблему, можно в теле функции использовать только одну переменную (в данном случае – MyEvent), присвоив ей, в случае для Explorer, значение объекта event:
function MyHandler(MyEvent) {
if (IE) MyEvent=event;
alert(MyEvent.screenX);
}
Здесь IE является результатом предварительной проверки на браузер, которая может выглядеть, например, так:
var IE = (navigator.appName=='Microsoft Internet Explorer');
При необходимости, можно также явно создать новые свойства для my_event и присвоить им значения фирменных расширений. Это позволит в дальнейшем использовать один и тот же код для в качестве универсального для всех браузеров. Например, для Mozilla можно создать свойство offcetX и присвоить ему значение свойства layerX:
if (!MyEvent.offcetX) MyEvent.offcetX = MyEvent.layerX;
В результате код функции, предназначенный для получения сведений о горизонтальной координаты курсора мышки относительно текущего объекта, может быть таким:
function MyHandler(MyEvent) {
if (IE) MyEvent=event;
if (!MyEvent.offcetX) MyEvent.offcetX = MyEvent.layerX;
result MyEvent.offcetX;
}
Таким образом, мы создали функцию, которая будет работать практически в любом браузере, что само по себе очень неплохо для такого капризного объекта, как Event. Пример использования этого объекта для исследования самого себя в контексте используемого браузера, можно посмотреть в файле event.html.
При помощи всплывания событий можно также отменять действия. Например, при щелчке по ссылке пользователь попадает на новую страницу. Однако при большом желании это можно отменить. Для этого элементу-ссылке потребуется назначить следующий обработчик события:
function stop_event() {
event.returnValue=false; // отменяем действие
event.cancelBubble=true; // запрещаем всплывание
}
Здесь функция stop_event(), предназначенная для перехвата события щелчка по ссылке, устанавливает возвращаемое значение в ложь и запрещает дальнейшее всплытие. Правда, в Mozilla последний пример не сработает по той причине, что фирменное свойство Microsoft – returnValue – в этом браузере не поддерживаются. Зато в нем реализованы стандартные методы preventDefault и stopPropagation, обращение к которым по сути аналогично назначению «false» свойствам returnValue и cancelBubble:
function stop_event(event1) {
event1.preventDefault(); // отменяем действие
event1.stopPropagation(); // запрещаем всплывание
}
Что касается браузера Opera, то он, в принципе, поддерживает оба варианта, но, поскольку всегда предпочтительнее опираться на официально принятые стандарты, то для него лучше использовать тот же код, что и для Gecko и WebKit. В итоге универсальная функция по блокировке события примет такой вид:
function stop_event(event1) {
if (navigator.appName=='Microsoft Internet Explorer') {
event.returnValue=false; // отменяем действие
event.cancelBubble=true; // запрещаем всплывание
} else {
event1.preventDefault(); // отменяем действие
event1.stopPropagation(); // запрещаем всплывание
}
}
Наконец, чтобы связать эту функцию с той или иной ссылкой (пусть она будет 2-й в документе), используем следующий код:
document.links[1].onclick=stop_event;
Этот пример вы также найдете в файле event.html – попробуйте пощелкать по ссылкам в разных браузерах, и посмотрите что получится.
2011-08-05 // Есть вопросы, предложения, замечания? Вы можете обсудить это на форуме !