Глава 3. Модель событий динамического HTML



События (events) представляют собой извещения, которые генерируются в результате действий пользователя или изменения состояния документа или окна. Динамический HTML предоставляет набор событий, позволяющих Web-мастеру определять реакцию на большую часть взаимодействий между пользователем и документом. Определяя реакцию на события, автор может создавать полностью интерактивные страницы.

В данной главе будут рассмотрены методы обработки событий. Глава заканчивается демонстрацией приложения, которое объединяет элементы встроенной поддержки динамического HTML с возможностями указателей функций JavaScript для создания механизма связывания событий.

В главе рассмотрены следующие темы:



Общая модель событий

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



Всплывание событий

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

Всплывание событий отсутствовало в ранних версиях объектной модели HTML, поскольку тогда оно не требовалось. В прошлом разработчики браузеров рассматривали лишь несколько элементов, которые могли генерировать события. В динамическом HTML все элементы генерируют события. Это значит, что теперь все элементы на странице - каждый тег P, H1 и так далее - не только могут, но и генерируют события. Переход к генерации событий всеми элементами мог бы сильно усложнить сценарии. Но с появлением всплывания событий сценарии стали более мощными и их стало проще писать.

В приведенном ниже коде тело документа, ссылка и изображение имеют связанные с ними события:

<HTML>
<HEAD>
<TITLE>Иди домой!</TITLE>
</HEAD>
<BODY>
<A HREF="home.htm"><IMG SRC="home.gif">Иди домой</A>
</BODY>
</HTML>

Без всплывания событий код обработчика событий для всех событий нажатия кнопки, которые происходят на ссылке, был бы очень сложным. Данный обработчик событий требовалось бы написать дважды: один раз для изображения и второй раз для ссылки. Такая избыточность была бы необходима, поскольку если пользователь щелкает мышью по изображению, то изображение получает событие, и если пользователь щелкает по тексту ниже изображения, то ссылка получает событие. Применение всплывания событий решает данную проблему. При использовании всплывания событий нажатие кнопки мыши сначала на изображении приводит к генерации события для изображения. Затем автоматически событие генерируется для ссылки. После чего событие возникает в теле документа и, наконец, в самом документе. Всплывание событий позволяет обрабатывать событие на каждом уровне иерархии контейнеров. В приведенном выше примере кода один обработчик событий нажатий кнопки на ссылке будет также обрабатывать щелчки мышью по изображению.



Действия по умолчанию

Помимо всплывания событий многие события имеют действия по умолчанию. Действие по умолчанию является действием, которое браузер выполняет в ответ на событие. Например, действием по умолчанию в ответ на нажатие ссылки <А HREF= "... "> является переход по указанному адресу и загрузка страницы.

В объектной модели динамического HTML можно заменять существующие действия по умолчанию на индивидуальную модель поведения. Если событие не имеет действия по умолчанию и создается индивидуальная модель поведения, то рекомендуется отменить возможное действие по умолчанию. Это гарантирует правильное выполнение программы, если действие по умолчанию будет позднее поддерживаться браузером.

Действие по умолчанию не всегда определяется источником события - оно может определяться родительским элементом. В приведенном выше примере, когда пользователь нажимает кнопку мыши на изображении, действие по умолчанию по переходу к указанной ссылке определяется элементом Anchor (ссылка), который содержит изображение. Однако если изображение отменяет действие по умолчанию для события, то действие по умолчанию для данной ссылки больше не будет действовать, поскольку действие по умолчанию может быть отменено любым элементом в цепочке событий. После того как обработчик событий устанавливает отмену действия по умолчанию, оно отменяется для всей цепочки событий.

Всплывание событий и действия по умолчанию представляют собой различные концепции, которыми можно управлять независимо. Например, если изображение останавливает событие в момент всплывания к ссылке, но не отменяет действие по умолчанию, то действие по умолчанию для ссылки будет применено к событию и будет осуществлен переход по ссылке. Обратное также справедливо: если ни ссылка, ни изображение не отменят действие по умолчанию, но действие по умолчанию отменяется, когда событие достигает элемента Body, то переход по ссылке не будет осуществлен. Свойства для отмены действия по умолчанию или остановке всплывания события описаны в разделе "Объект event" ниже в данной главе.



Связывание событий

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

Независимые от языка механизмы связывают события посредством атрибутов элемента Script, посредством специальных атрибутов HTML, связанных непосредственно с определенным элементом или посредством объектной модели. VBScript также предлагает механизм связывания в стиле Visual Basic, который включает в себя установку имен подпроцедур обработчика определенным способом.



Атрибуты событий

В динамическом HTML все элементы документа были изменены для поддержки событий клавиатуры и мыши. Данные события представлены как атрибуты непосредственно для каждого элемента, что позволяет устанавливать прямую связь между элементом и его поведением. Данная связь сходна со связью между элементом и встроенным стилем при использовании атрибута STYLE. Например, можно связать событие onclick (нажатие кнопки) с функцией с помощью атрибута, как показано в приведенном ниже примере:

<!-- Когда пользователь щелкает по кнопке мыши, вызывается функция foo(). -->
<INPUT TYPE=BUTTON VALUE="Нажмите здесь" ONCLICK="foo();" LANGUAGE="JavaScript">

Атрибут ONCLICK может вызвать функцию или немедленно выполнить одну или большее число строк кода. В данном примере, когда пользователь нажимает кнопку мыши, вызывается процедура foo. Атрибут LANGUAGE определяет язык, на котором написана программа. Пропуск атрибута LANGUAGE устанавливает по умолчанию язык, указанный на первой странице или JavaScript в отсутствие других сценариев. Приведенный ниже пример демонстрирует две встроенных инструкции, которые выполняются при нажатии пользователем кнопки:

<!-- При нажатии кнопки мыши отображать сообщение и затем вызвать функцию foo(). -->
<INPUT TYPE=BUTTON VALUE="Нажмите здесь"
ONCLICK="alert('Пользователь нажал здесь.'); foo();"
LANGUAGE="JavaScript">

Кнопка сначала выводит окно сообщения, а затем вызывает функцию foo.

Все атрибуты HTML являются нечувствительными к регистру, регистр символов не имеет значения при использовании атрибутов, например ONCLICK, для связывания обработчиков с событиями. Чувствительность к регистру может быть важна, когда используются другие механизмы связывания событий. Связывание событий с атрибутами HTML удобно, но имеет ряд недостатков. Первый недостаток заключается в том, что требуется расширять язык HTML каждый раз при изобретении нового события. Например, в приведенном выше примере событие onclick подразумевает расширение определения типа документа (DTD, document type definition) за счет включения в тег <INPUT> атрибута ONCLICK. Это усложняет добавление событий стандартным способом, поскольку HTML развивается медленно. Более того, объекты или приложения, которые генерируют произвольные события, также требуют расширения языка или представления их собственных методов связывания событий. Поэтому данный подход используется только для небольшого набора встроенных событий. Если в страницу внедрен произвольный объект, то его события представлены более общим способом.



Поддержка общих событий

Второй механизм связывания лишен указанных выше недостатков. Данный механизм использует новые расширения элемента Script - атрибуты FOR и EVENT - для связывания функций с событиями. Атрибут EVENT ссылается на событие и все параметры, которые ему могут быть переданы. Атрибут FOR указывает имя или идентификатор (ID) элемента, для которого написано событие. Например, событие onmousemove представлено в документе. Вы можете использовать тег <SCRIPT> для связывания с данным событием:

<SCRIPT FOR="document" EVENT="onmousemove()" LANGUAGE="JavaScript">
// Данный обработчик событий вызывается, когда указатель мыши // перемещается по документу.
</SCRIPT>

Примечание: JavaScript является чувствительным к регистру для обоих значений атрибутов EVENT и FOR тега <SCRIPT>. Следует убедиться, что все имена событий набраны в нижнем регистре для встроенных событий и в соответствующем регистре для внедренных объектов. Кроме того, если вы определяете идентификатор (ID) в атрибуте FOR, вы должны набрать их в точном соответствии с тем, как они набраны в атрибуте ID самого элемента. Если событие не возникает, то всегда проверяйте правильность ввода символов и регистра в теге <SCRIPT>.

Следует принять к сведению следующее предостережение относительно приведенного выше синтаксиса. Netscape Navigator игнорирует атрибуты FOR и EVENT и попытается выполнять программу немедленно. В приведенном ниже коде используется прием для обхода данного ограничения:

<SCRIPT LANGUAGE="JavaScript">
// Предположим, что браузер поддерживает атрибут FOR.
var ForSupport = true;
</SCRIPT>
<SCRIPT FOR="fakeObject" EVENT="foo" LANGUAGE="JavaScript">
// Данное событие не существует.
// Если атрибуты FOR и EVENT поддерживаются, то данный код не будет // выполняться. ForSupport = false;
</SCRIPT>
<SCRIPT FOR="document" EVENT="onmousemove" LANGUAGE="JavaScript">
if (ForSupport) {
// Код действительного обработчика событий.
} else
alert("Ваш браузер не поддерживает необходимый синтаксис события.");
</SCRIPT>

Для того чтобы гарантировать, что код сценария не будет выполняться, следует указать, что используется язык JScript. JScript представляет собой реализацию JavaScript компании Microsoft. Поскольку Microsoft Internet Explorer является единственным браузером, который поддерживает JScript, в сценарии не требуется инструкция if, которая должна быть проигнорирована Netscape.

<SCRIPT FOR="document" EVENT="onmousemove()" LANGUAGE="JScript">
// Данный обработчик событий вызывается, когда указатель мыши перемещается
// по документу, если браузер поддерживает ядро языка JScript.
</SCRIPT>

Примечание: При указании имени события скобки необязательны. Например, приведенное выше событие может быть определено как EVENT= "onmousemove".



Связывание событий в стиле Visual Basic

Помимо обсуждавшихся выше методов язык VBScript также поддерживает механизм связывания сценариев с событиями в стиле Visual Basic. Visual Basic традиционно связывает код с событием с помощью специальной процедуры. Если процедура написана в формате Visual Basic, то ядро Visual Basic знает, какие события должны быть связаны со сценарием. Например, приведенный ниже код связывает событие onmousemove с событием onclick в документе:

<SCRIPT LANGUAGE="VBScript">
Sub document_onMouseMove()
'Обработчик событий для перемещения указателя мыши по документу.
End Sub
Sub document_onClick()
' Обработчик событий для нажатий кнопки мыши в документе.
End Sub
</SCRIPT>

Примечание: Microsoft Internet Explorer 3.0 также поддерживает приведенный выше синтаксис в JScript, но данный синтаксис не поддерживается в Netscape Navigator или Internet Explorer 4.0. Поэтому данный метод не следует использовать с JScript.

В VBScript преимущество использования данной модели заключается в том, что могут быть написаны многочисленные обработчики событий внутри одного блока сценария. Главный недостаток заключается в том, что внешние инструменты не могут просто определить события, которые были написаны для них обработчиками событий. Использование синтаксиса атрибутов FOR и EVENT элемента Script или синтаксиса атрибута встроенных событий HTML дает возможность быстро сканировать документ и определять события, с которыми связан код. Модель связывания в стиле Visual Basic будет распознана только специально написанным инструментом.

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



Определение языков написания сценариев в атрибутах событий

Вы можете определить различные языки для каждого встроенного атрибута события HTML. Атрибут LANGUAGE, который используется со встроенными атрибутами событий HTML, определяет язык по умолчанию для интерпретации кода. Для изменения установленного по умолчанию языка следует указать необходимое значение идентификатора языка в атрибуте события. Формат данного идентификатора приведен ниже:

<Element EventName="Language:Code">

Идентификатор Language представляет собой независимую от регистра строку, которая определяет язык написания сценариев для программы Code. Internet Explorer 4.0 поддерживает следующие языки: JScript, JavaScript, JavaScript 1.1 и VBScript. Языки JScript, JavaScript и JavaScript 1.1 запускают одно ядро языка. Обработчики onclick и omnousedown в приведенном ниже теге <BODY> определены в различных языках написания сценариев:

<BODY ONCLICK="JavaScript:dothis(this);"
ONMOUSEDOWN="VBScript:dothat(me)">

Netscape Navigator не поддерживает указанные языки для значения атрибута события. Netscape Navigator и Internet Explorer поддерживают указанные языки для атрибута HREF ссылок, что позволяет создать код JavaScript или VBScript, который будет выполняться при щелчке по ссылке. Однако Netscape Navigator распознает только JavaScript и попытается перейти на недействительную страницу, если указаны другие языки.



События как свойства

Все события также представлены как свойства в объектной модели динамического HTML. Все имена свойств вводятся в нижнем регистре и начинаются с префикса on. Цель представления данных событий и свойств событий заключается в активизации событий для динамического связывания с функциями во время выполнения. Для всех свойств событий может быть назначен указатель функции.

Поддержка указателей функций зависит от языка программирования. JavaScript поддерживает указатели функций, но VBScript не поддерживает данные указатели. Поэтому VBScript не может динамически генерировать обработчиков событий. (Однако вы можете использовать код VBScript для назначения функции JavaScript событию). При возникновении события вызывается функция, указанная в свойстве.

<HTML>
<HEAD>
<TITLE>Пример указателя функции</TITLE>
</HEAD>
<BODY>
<INPUT TYPE=BUTTON ID="myButton" VALUE="Click here">
<SCRIPT LANGUAGE="JavaScript">
// Присоединение указателя функции к myButton. // При нажатии кнопки myButton отображается окно сообщения.
document.all.myButton.onclick = new Function("alert('Hello');");
</SCRIPT>
</BODY>
</HTML>

Для назначения указателя функции укажите имя функции прямо в свойстве.

<HTML>
<HEAD>
<TITLE>Назначение указателя функции</TITLE>
<SCRIPT LANGUAGE="JavaScript">
// Определение функции clicked.
function clicked() {
alert("Clicked");
}
</SCRIPT>
</HEAD>
<BODY>
<INPUT TYPE=BUTTON ID="myButton" VALUE="Click here">
<SCRIPT LANGUAGE="JavaScript">
// Назначение функции clicked обработчику события onclick.
document.all.myButton.onclick = clicked;
</SCRIPT>
</BODY>
</HTML>

Примечание: При назначении указателя функции используйте только имя функции. Круглые скобки и дополнительные параметры не требуются. Если они будут указаны, то функция будет выполнена. В результате чего свойству будет назначено возвращаемое функцией значение, вместо указателя на функцию.



Расписание связывания событий

Последовательность, в которой обработчики событий связываются с элементами, определяется языком написания сценария. JavaScript подключает события асинхронно по мере загрузки страницы. Каждый элемент Script и атрибут события подключаются по мере анализа документа. VBScript не связывает события до тех пор, пока вся страница не будет проанализирована, все внешние сценарии загружены и внедренные объекты не начнут загружаться.

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

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

<HTML>
<HEAD>
<TITLE>Пример анализа</TITLE>
<SCRIPT LANGUAGE="JavaScript">
function doClick() {
if (isLoaded) {
// Запуск обработчика событий.
}
else {
alert("Пожалуйста, подождите пока документ не будет загружен.");
}
}
</SCRIPT>
</HEAD>
<BODY>
<INPUT TYPE=BUTTON ID="myInput" VALUE="Click here"
ONCLICK="doClick()">
<SCRIPT LANGUAGE="JavaScript">
// Данный элемент будет последним элементом, который анализируется
// в документе.
isLoaded = true;
</SCRIPT>
</BODY>
</HTML>

С помощью обработчика событий можно также проверить, была ли страница проанализирована целиком. Два события могут быть использованы для выполнения этой задачи: событие event в окне и событие onreadystatechange в документе. Событие onload возникает, когда документ целиком проанализирован и все элементы загружены. Более мощное событие onreadystatechange в документе, которое поддерживается только в Internet Explorer 4.0, возникает несколько раз по мере того, как документ проходит несколько состояний загрузки и возникает в последний раз, когда документ полностью загружен.

События onload и onreadystatechange подробно обсуждаются в главах 4 и 6.



Область действия сценариев

Все обработчики событий ограничены элементом, с которым связан обработчик. Данный элемент представлен в языке написания сценариев JavaScript с помощью свойства this, а в VBScript с помощью свойства me.

Область действия события необязательно ограничена элементом, который первым сгенерировал событие. Элемент, который первым сгенерировал событие, представлен свойством srcElement в объекте event.

Объект event подробно обсуждается в разделе "Объект event" ниже в данной главе.

Управление указателем this

Приведенный ниже код демонстрирует три различных способа связывания обработчика с событием. Все три обработчика эквивалентны.

<INPUT NAME="myBtn" TYPE=BUTTON VALUE="My Button"
onClick="alert(this.name);" LANGUAGE="JavaScript">

или

<SCRIPT FOR="myBtn" EVENT="onclick()" Language="JavaScript">
alert(this.name);
</SCRIPT>

или

<SCRIPT LANGUAGE="JavaScript">
myBtn.onclick = new Function("alert(this.name)");
</SCRIPT>

В этих примерах элемент this.name возвращает значение элемента myBtn, поскольку ссылка на элемент дается прямо во встроенном коде или сценарии. Если требуется сослаться на элемент в процедуре, вызываемой обработчиком событий, то потребуется передать элемент в процедуру с помощью ключевого слова this. Например, приведенный ниже код отобразит пустую строку вместо текста myBtn, поскольку указатель this в функции foo ссылается на саму функцию, вместо элемента, который генерирует событие:

<SCRIPT LANGUAGE="JavaScript"> function foo() {
// Указатель this не ссылается на кнопку.
alert(this.name);
}
</SCRIPT>
<INPUT TYPE=BUTTON NAME="myBtn" VALUE="My Button"
ONCLICK="foo();" LANGUAGE="JavaScript">

Вместо этого вы должны передать ссылку на элемент myBtn в функцию foo, используя ключевое слово this:

<SCRIPT LANGUAGE="JavaScript"> function foo(b) {
// Аргумент b ссылается на кнопку, поскольку она передается
// обработчиком событий.
alert(b.name);
}
</SCRIPT>
<INPUT TYPE=BUTTON NAME="myBtn" VALUE="My Button"
ONCLICK="foo(this);" LANGUAGE="JavaScript">

Указатель this также автоматически устанавливается, когда обработчик событий назначается в качестве указателя функции:

<H1 ID="myH1">Это заголовок.</H1>
<SCRIPT LANGUAGE="JavaScript">
function clickHandler() {
// Свойство thia указывает на элемент, с которым связан обработчик.
alert(this.tagName)
}
// Указатель функции не должен передавать указатель this.
document.all.myH1.onclick = clickHandler; </SCRIPT>

Имена во встроенном коде идентифицируются путем поиска членов объектной модели в следующем порядке:

  1. Все свойства текущего элемента.

  2. Все элементы представлены для пространства имен - например, в форме, элементы управления в форме.

  3. Свойства элемента, содержащего пространство имен, - например, свойства формы для элементов внутри формы.

  4. Свойства документа.



Разделяемые обработчики событий

JavaScript поддерживает создание разделяемого обработчика событий. В JavaScript все элементы, которые совместно используют одно имя, могут также совместно использовать одинаковые обработчики событий с помощью атрибутов FOR и EVENT элемента Script:

<SCRIPT FOR="gender" EVENT="onclick()" LANGUAGE="JavaScript">
// Данный обработчик событий выполняется при нажатии любого элемента // с именем или идентификатором "ID".
</SCRIPT>
<INPUT TYPE=RADIO NAME="gender" VALUE="Male">
<INPUT TYPE=Radio NAME="gender" VALUE="Female">

Данный метод работает только в JavaScript. VBScript может запускать обработчика событий таким образом только на основе уникального идентификатора ID элемента, а не его имени NAME. Если бы данный код был переписан на VBScript, то потребовалось бы указать уникальные значения идентификаторов для кнопок-переключателей и написать отдельный обработчик событий для каждой кнопки.

Альтернативой VBScript, которая также работает для любого языка написания сценариев, является использование процедуры всплывания событий и отслеживание события, начиная с родительского контейнера:

<SCRIPT FOR="GenderGroup" EVENT="onclick()" LANGUAGE="VBScript">
' Данный обработчик событий выполняется при нажатии любого элемента в
' блоке GenderGroup.
If "gender" = window.event.srcElement.name Then
' Пользователь нажал кнопку-переключатель.
End If
</SCRIPT>
<DIV ID="GenderGroup">
<INPUT TYPE=Radio NAME="gender" VALUE="Male">
<INPUT TYPE=Radio NAME="gender" VALUE="Female">
</DIV>



Объект event

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

Динамический HTML представляет независимый от языка механизм доступа к информации, связанной с событием, и управления всплыванием события и возникновением действия по умолчанию. Данная информация представлена посредством объекта event, который является свойством объекта window.

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

Свойство srcElement возвращает элемент, который первым сгенерировал событие. Например, при нажатии изображения home.gif в примере HTML-страницы в начале данной главы изображение является свойством srcElement по мере того, как событие всплывает через ссылку, тело и документ.

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

Свойство returnValue используется преимущественно для отмены действия по умолчанию события. Не все события имеют действия по умолчанию. Однако если вы пишете код, который изменяет поведение события, то всегда отменяйте действие по умолчанию так, чтобы если действие по умолчанию будет добавлено к событию в будущем, то поведение страницы не изменилось. Для отмены действия по умолчанию для данного свойства должно быть установлено значение false.

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

Примечание: JavaScript поддерживает возвращение значений непосредственно обработчику событий, используя ключевое слово return. Ключевое слово return обновляет свойство returnValue объекта event, когда обработчик событий возвращает управление браузеру.

Объект event устанавливается для каждой последовательности событий. Поэтому любые назначения объекта event применимы только к экземпляру последовательности событий. При следующем возникновении события объект event сбрасывается. Отмена действия по умолчанию, например, отменяет только действие по умолчанию для текущего события, а не для всех последующих событий. По этой причине к объекту event должен обращаться обработчик событий, а не код, который выполняется в ходе загрузки страницы.



Определение события

Объект event представляет тип события посредством свойства type. Свойство type возвращает имя события в нижнем регистре без префикса on. Например, событие onmousedown возвращается как mousedown, событие onclick - как click и так далее. Зная тип события, один обработчик может различать и обрабатывать различные события:


function handleEvent() {
// Запуск обычного обработчика событий.
switch (event.type) {
case "click":
// Обработка события onclick.
break;
case "mousedown":
// Обработка события onmousedown.
break;
}
}
// Присоединяет события к обработчику событий handleEvent. document.onclick = handleEvent;
document.onmousedown = handleEvent;



Доступ к параметрам посредством объекта event

Объект event представляет все параметры встроенных событий как свойства. Например, информация о текущем положении указателя мыши доступна для всех событий. Некоторая информация доступна только для определенного события. События мыши также обеспечивают доступ к текущему состоянию кнопок мыши. Данные параметры инициализируются и обновляются до генерации события. Приведенный ниже пример иллюстрирует процедуру доступа к параметрам события:

<SCRIPT FOR="document" EVENT="onmousedown()" LANGUAGE="JavaScript">
// Вывод состояния кнопки мыши при ее нажатии.
alert("x:" + event.clientX);
alert("y:" + event.clientY);
alert("button:" + event.button);
alert("Source Element:" + event.srcElement.tagName);
</SCRIPT>



Координаты мыши

Объект event представляет свойства, которые определяют положение указателя мыши на основе различных систем координат. Свойства событий мыши перечислены в табл. 3.1.

Таблица 3.1. Свойства событий мыши


Свойство Описание

clientX, clientY Горизонтальные и вертикальные координаты указателя мыши относительно клиентской области окна
offsetX, offsetY Горизонтальные и вертикальные координаты указателя мыши относительно контекста воспроизведения
screenX, screenY Горизонтальные и вертикальные координаты указателя мыши относительно экрана

На рис. 3.1 проиллюстрированы взаимоотношения между различными координатами.

Создание систем координат и контекстов воспроизведения обсуждается в главе 12.

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

Рис. 3.1. Начала координат указателя мыши объекта event в различных системах



Информация клавиш и кнопок

Свойства объекта event представлены в табл. 3.2 и определяют текущие клавиши и кнопки мыши, нажатые во время события.

Таблица 3.2. Свойства объекта event


Параметр Значение

button Набор значений, соответствующих нажатым кнопкам мыши:
0 - Кнопки не были нажаты
1 - Была нажата левая кнопка
2 - Была нажата правая кнопка
4 - Была нажата средняя кнопка
Параметр button представляет комбинированное состояние всех кнопок мыши. Например, если были нажаты левая и правая кнопка мыши, то параметр button возвращает 3
ctrlKey Логическое значение, указывающее на нажатие клавиши <Ctrl>
altKey Логическое значение, указывающее на нажатие клавиши <Alt>
shiftKey Логическое значение, указывающее на нажатие клавиши <Shift>

Данные свойства полезны при написании глобального обработчика событий для документа. Используя координаты мыши вместе с методами elementFromPoint или rangeFromPoint В документе, можно проверить положение указателя мыши на определенном элементе или в точке текста:


<SCRIPT EVENT="onkeypress()" FOR="document" LANGUAGE="JavaScript">
// Определяет элемент, на котором находится указатель мыши при нажатии
// кнопки.
// Методы fromPoint основаны на координатах клиента.
var e = document.elementFromPoint(event.clientX, event.clientY);
if ("H1" == e.tagName) {
// Здесь должны быть указаны операции, которые выполняются при // нажатии кнопки, когда указатель мыши находится на элементе H1.
}
</SCRIPT>



Программирование стандартных пользовательских событий

Стандартные пользовательские события представляют собой набор событий, совместно используемых всеми элементами для реагирования на действия пользователя. Данные события служат для отслеживания мыши и клавиатуры, передачи фокуса между элементами и прокручивания любой полосы прокрутки. Многие элементы используют события, специально предназначенные для выполнения задачи элемента. Например, элементы форм имеют события onsubmit и onreset.

Эти дополнительные события вместе с соответствующими элементами обсуждаются в главах 8-10.



События мыши

Объектная модель динамического HTML представляет события для отслеживания различных состояний мыши, включая перемещение указателя мыши над элементами и нажатие кнопок мыши. В табл. 3.3 перечислены события мыши.

Таблица 3.3. События мыши


Событие Описание

omnousedown Была нажата кнопка мыши
onmousemove Перемещается или был перемещен указатель мыши
onmouseup Была отпущена кнопка мыши
onclick Была нажата левая кнопка мыши или вызвано действие по умолчанию данного элемента
ondblclick Была дважды нажата левая кнопка мыши
onmouseover Указатель мыши был перемещен в область элемента
onmouseout Указатель мыши был выведен из области элемента
ondragstart Была запущена операция перетаскивания
onselectstart Было инициировано новое выделение элемента с помощью мыши
onselect Был выделен элемент


События onclick и ondblclick

Событие onclick представляет собой в большей степени семантическое, чем физическое событие. Хотя событие onclick обычно возникает после нажатия левой кнопки мыши, оно может также возникнуть в результате действия, которое имитирует нажатие кнопки. Например, событие onclick возникает, когда пользователь нажимает клавишу <Enter> и фокус находится на какой-либо кнопке. Событие ondblclick возникает, когда пользователь дважды нажимает левую кнопку мыши в течение определенного системой периода времени.

При щелчке мышью по элементу событие onclick возникает после генерации событий onmousedown и onmouseup. Событие onclick не обязательно должно генерироваться для того же элемента, на котором возникли события onmousedown и onmouseup. Рассмотрим следующий код HTML:


<HTML>
<HEAD>
<TITLE>Правила нажатия </TITLE>
</HEAD>
<BODY>
<H1>Добро пожаловать на мою домашнюю страницу</H1>
<H2>Последняя информация о динамическом HTML</H2>
</BODY>
</HTML>

Если кнопка мыши была нажата, когда указатель мыши находился на элементе H1, то для данного элемента возникают события onmousedown, onmouseup и onclick. Если кнопка мыши была нажата на элементе H1 и отпущена на элементе Н2, то событие onmousedown возникает для элемента H1, a событие onmouseup возникает для элемента H2. Событие onclick возникает в теле документа как любое последовательное событие ondblclick, которое может возникнуть как часть данной последовательности, поскольку тело является общим элементом, на котором находится указатель мыши при отпускании кнопки мыши. Событие onmouseup возникает на элементе H2, а не на элементе H1, поскольку мышь установлена на текстовом элементе.

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

Поскольку события onclick и ondblclick могут возникнуть на элементе, который является общим для элементов, на которых кнопка мыши была нажата и отпущена, то данные, два события могут возникнуть на элементах, которые не являются концевыми узлами в дереве документа. Концевые узлы (leaf nodes) представляют собой самые глубокие узлы документа, которые служат для записи содержания. События onclick и ondblclick являются нестандартными пользовательскими событиями. С учетом нескольких исключений, которые будут введены в последующих главах, все остальные события мыши и клавиатуры всегда начинаются на концевых узлах и поднимаются (всплывают) вверх по иерархии.

Ниже перечислен порядок генерации событий onmouse и onclick:

  1. onmousedown
  2. onmouseup
  3. onclick

При возникновении двойного нажатия кнопки мыши последовательность событий продолжается следующим образом:

  1. onmouseup
  2. ondblclick

События onmouseover и onmouseout

События onmouseover и onmouseout возникают при подведении или снятии указателя мыши с элемента на странице. Данные события мыши представляют те же параметры, что и события onmousedown и onmouseup. Они возникают только один раз на концевых узлах документа и поднимаются вверх по иерархии элементов вместо возникновения при всех граничных условиях. Рассмотрим следующий код HTML:


<HTML>
<HEAD>
<TITLE>Через границы и за пределами границ</TITLE>
</HEAD>
<BODY>
<H1>Это заголовок.</H1>
<DIV>
<P><B>Добро пожаловать</B> на мою страницу.</P>
</DIV>
</BODY>
</HTML>

На данной HTML-странице при перемещении мыши по телу документа к полужирному тексту параграфа возникает одно событие onmouseevent на элементе Body, а событие onmouseover возникает на элементе B. Поскольку событие всплывает, то все элементы, границы которых пересекает событие, получают уведомление о событии.

Когда указатель мыши переходит от выделенного полужирным начертанием тексту к невыделенному тексту, то на данном элементе возникает событие onmouseout, которое всплывает через параграф. Это важно отметить, поскольку параграф может получить событие onmouseevent, когда указатель мыши все еще находится над параграфом.

Для точной проверки, сместился ли указатель мыши с элемента, используйте метод элемента contains наряду со свойством toElement события onmouseout, указывающим на новый элемент, к которому переместился указатель мыши. Метод contains указывает, содержится ли один элемент внутри другого элемента. С помощью простого кода можно проверить элемент назначения, чтобы выяснить, содержится ли он внутри другого элемента, на котором возникло событие. Если это так, то указатель мыши все еще находится на сгенерировавшем событие элементе. В данном примере обработчик событий onmouseout будет присоединен к событию onmouseout элемента для проверки того, что указатель мыши все еще находится на элементе:


<SCRIPT LANGUAGE="JavaScript">
function testexit(src) {
// Проверка, что указатель мыши действительно находится на элементе.
if (!src.contains(event.toElement)) {
// Указатель мыши сместился с элемента.
}
}
</SCRIPT>
<H1 ONMOUSEOUT="testexit(this);">Некоторый <EM>текст</EM></H1>

В данном примере указатель this, представляющий элемент, на котором возникло событие, должен быть передан в функцию. Свойство srcElement объекта event не может быть использовано вместо него, поскольку оно может быть дочерним элементом. Например, при перемещении указателя мыши через отмеченный текст в предыдущем заголовке именно отмеченный текст, а не заголовок H1, является элементом srcElement.

Этот метод работает при подведении указателя мыши к элементу, и почти идентичный код выполняется для события onmouseover. Единственное отличие заключается в том, что свойство fromElement следует проверить при помощи метода contains:


function testenter(src) {
if (!src.contains(event.fromElement)) {
// Указатель мыши подведен к элементу.
}
}

Событие onmouseover возникает, когда указатель мыши перемещается через элемент. Ниже приведен порядок генерации событий onmouseover, onmousemove и onmouseout при пересечении границы указателем мыши:

  1. onmouseout
  2. onmousemove (может возникнуть несколько раз).
  3. onmouseover


Событие ondragstart

В настоящее время динамический HTML обеспечивает ограниченную поддержку операций перетаскивания. Одиночное событие, связанное с перетаскиванием, представлено в объектной модели в качестве альтернативы поведения по умолчанию. Когда пользователь нажимает и, удерживая кнопку мыши, перетаскивает элементы документа, такие как изображения и ссылки, эти элементы принимают участие в операции перетаскивания.

Возможны случаи, когда такое поведение будет препятствовать выполнению авторских замыслов. Для отмены встроенного поведения представлено событие ondragstart. Данное событие в сущности служит выполнению одной цели - предоставить разработчику возможность отменить событие путем возвращения значения false.

Существует тесная связь между отменой события onmousemove и события ondragstart. Для предотвращения операции перетаскивания элемента отмените событие ondragstart. При создании собственных моделей операции перетаскивания элемента обычно также следует отменить событие onmousemove.

Пример в главе 12 моделирует перетаскивание путем использования события onmousemove для перемещения позиционированных элементов на экране. Данный метод хорошо работает при обеспечении поддержки перетаскивания внутри страницы.

Динамический HTML пока не позволяет программировать перетаскивание между фреймами и окнами.


События onselectstart и onselect

Динамический HTML представляет два события для полного отслеживания выбора пользователя в документе: onselectstart и onselect, которые запускаются в порядке перечисления.

Подобно событию ondragstart событие onselectstart запускается только если должен быть сделан выбор, обычно когда пользователь щелкает мышью по некоторому элементу в документе. Цель данного события заключается в запрещении выделения области документа. Важно учесть, что это предотвращает только инициализацию выделения фрагмента. Например, в приведенном ниже документе, если пользователь не может выделить строку Scott's Page.


<HTML>
<HEAD>
<TITLE>onselectstart Пример</TITLE>
</HEAD>
<BODY>
<H1>Welcome to <EM STYLE="cursor:hand"
ONSELECTSTART="event.returnValue=false;">Scott's Page
</EM>
</H1>
</BODY>
</HTML>

Однако если пользователь щелкает кнопкой мыши по тексту за пределами строки Scott's Page и перетаскивает указатель мыши через строку Scott's Page, то текст будет выделен, поскольку отменена только инициализация выделения.

Свойство CSS cursor используется для изменения указателя мыши на значок "рука". Путем добавления обработчика событий onclick можно определить индивидуальное действие, которое произойдет, если пользователь щелкнет по строке. Комбинация свойства cursor и обработчика событий onselectstart обеспечивает уровень управления, одинаковый с доступным по умолчанию для ссылок.

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

Событие onselect следует за событием onselectstart и возникает во время выделения текста. Оно возникает много раз по мере того, как пользователь расширяет или сужает выделение. Событие onselect не всплывает. Оно возникает в разделе документа, в котором производится выделение фрагмента в элементе документа Body для текстового содержания или в элементах управления вводом.


События клавиатуры

Динамический HTML обеспечивает три события для отслеживания нажатий клавиш пользователем: onkeydown, onkeyup и onkeypress, которые возникают в этом порядке. События onkeydown и onkeyup возникают при нажатии и отпускании клавиши на клавиатуре. Событие onkeypress возникает при нажатии любой клавиши <ANSI>.

Событие event представляет четыре свойства для определения состояния, клавиатуры при возникновении данных событий, приведенные в табл. 3.4. Свойства shiftKey, altKey и ctrlKey совпадают со свойствами для событий мыши.

Таблица 3.4. Свойства события event для определения состояния клавиатуры


Свойство Значение

keyCode ASCII-код нажатой клавиши. Установка данного свойства равным нулю в обработчике события onkeypress отменяет событие. Установка данного свойства равным положительному значению заменяет нажатую клавишу на клавишу с отличным значением ASCII
shiftKey Состояние клавиши <Shift> (true/false)
altKey Состояние клавиши <Alt> (true/false)
ctrlKey Состояние клавиши <Ctrl> (true/false)



Событие прокручивания

Элемент Body, а также многие другие элементы, могут иметь полосы прокрутки. Когда один из этих элементов или его полоса прокрутки прокручивается, возникает событие onscroll. Событие прокручивания возникает, когда пользователь явно прокручивает полосу прокрутки или неявно прокручивает элемент посредством другого действия. Например, нажатие ссылки в закладке генерирует событие onscroll, если требуется прокрутить документ для просмотра элемента. Событие onscroll не может отменить прокручивание, поскольку запускается после завершения прокручивания. Данное событие возникает только для прокручиваемого элемента (например, для элемента Body) и не всплывает.



События фокуса

Динамический HTML предоставляет два события, связанных с фокусом: onfocus и onblur. Событие onfocus возникает, когда элемент активизируется после щелчка по нему мышью или с помощью клавиатуры. Элемент, который потерял фокус, получает событие onblur. Фокус могут получать только элементы пользовательского ввода и тело документа. Поэтому щелчок по содержанию HTML-документа приводит к получению события onfocus телом документа, а не элементами содержания.

Событие onblur также возникает, когда другое приложение или окно активизируется в текущем фрейме или приложении. Поэтому при переключении между окнами текущий элемент получает событие onblur. Событие onfocus возникает для данного элемента при возвращении в окно.

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



Событие help

Документ представляет событие help, которое возникает, когда пользователь запрашивает файл справки для документа, используя клавишу <F1>. Данное событие не возникает, когда пользователь выбирает пункт Help из меню Help. Событие onhelp сначала возникает на элементе с фокусом и затем всплывает вверх по иерархии. Действие по умолчанию для данного события заключается в отображении встроенного файла справки, но данное событие может быть отменено для отображения индивидуального файла справки.

Событие onhelp также возникает в модальных диалоговых окнах, которые поддерживают контекстно-зависимую справку посредством значка Help в строке заголовка. Путем нажатия значка Help пользователь может изменить вид указателя мыши на специальный курсор справки. Когда пользователь выбирает элемент, используя данный курсор, то на элементе возникает событие onhelp, которое затем всплывает к родительским объектам.

Обработчик события onhelp обычно отображает индивидуальный файл справки. Обработчик может вызвать метод showHelp для отображения файла справки Windows (HLP) или метод open для отображения файла HTML. Методы showHelp и open являются методами объекта window. Метод showHelp может также отображать HTML-файлы, но метод open поддерживается большим количеством браузеров и предлагает больше возможностей для управления отображаемым окном.

Метод open описан в главе 5.



Примеры событий

В данном разделе приведены две программы, иллюстрирующие возможности архитектуры событий, описываемой в данном разделе. С помощью примера Event Tutor вы можете проверить страницу и просмотреть события, которые возникают при взаимодействии с ней.

Код примера Event Broadcaster предоставляет общий механизм захвата несколькими обработчиками каждого события.



Event Tutor

Для лучшего изучения всплывания событий в число примеров, находящихся на прилагаемом компакт-диске для главы 3, включен HTML-документ с названием tutor.htm, который может показать все события, возникающие на странице. На рис. 3.2 показано приложение Event Tutor.

Рис. 3.2. Приложение Event Tutor

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

Ниже приведен исходный код из файла events.htm, используемый для создания примера Event Tutor. Данный код демонстрирует отслеживание событий через фреймы - метод, который подробно обсуждается в главе 5.

В примере использована модель представления объектов как связанных массивов и создания индивидуальных функций, принятия в JavaScript.


<HTML>
<HEAD>
<TITLE>Event Tutor</TITLE>
<STYLE TYPE="text/css">
caption {font-weight:bolder; color:navy}
</STYLE>
<SCRIPT LANGUAGE="JavaScript">
// Данный пример доступен только на JavaScript (This example is // available in JavaScript only) function outputEvent(src, eventName) {
// Присоединение имени события к текстовой области (Append // event name to text area control.)
document.all.txtEvents.value += eventName + ": " +
src.tagName + "\n";
}
function setupEvents() {
// Пользователь установил флажок.
// HЗахват или удаление обработчиков событий.
if ("checkbox" == event.srcElement.type) {
var handler = event.srcElement.checked ?
new Function("outputEvent(this, '" +
event.srcElement.id + "')") :
null;
var allSample = parent.frames.sample.document.all;
// Добавление индивидуального обработчика событий для всех
// элементов в другом фрейме.
for (var intLoop=0; intLoop < allSample.length;
intLoop++) {
// Обращение к свойству событий, которое соответствует
// идентификатору установленного флажка
allSample[intLoop][event.srcElement.id] = handler;
}
}
}
</SCRIPT>
</HEAD>
<BODY>
<FORM NAME="EVENTS">
<TABLE WIDTH=100% ONCLICK="setupEvents()" CELLPADDING=4>
<CAPTION>Events</CAPTION>
<TR VALIGN="Top"><TD NOWRAP>
<!-- Обратите внимание на соглашения об именовании, которые используются ниже. Для добавления событий идентификатор должен указать имя события. -->
<INPUT TYPE=CHECKBOX ID=onmousedown>
<LABEL FOR=onmousedown>MouseDown</LABEL><BR>
<INPUT TYPE=CHECKBOX ID=onmouseover>
<LABEL FOR=onmouseover>MouseOver</LABEL><BR>
<INPUT TYPE=CHECKBOX ID=onmousemove>
<LABEL FOR=onmousemove>MouseMove</LABEL><BR>
<INPUT TYPE=CHECKBOX ID=onmouseout>
<LABEL FOR=onmouseout>MouseOut</LABEL><BR>
<INPUT TYPE=CHECKBOX ID=onmouseup>
<LABEL FOR=onmouseup>MouseUp</LABEL><BR>
<INPUT TYPE=CHECKBOX ID=onkeydown>
<LABEL FOR=onkeydown>KeyDown</LABEL><BR>
<INPUT TYPE=CHECKBOX ID=onkeypress>
<LABEL FOR=onkeypress>KeyPress</LABEL><BR>
<INPUT TYPE=CHECKBOX ID=onkeyup>
<LABEL FOR=onkeyup>KeyUp</LABEL>
</TD><TD NOWRAP>
<INPUT TYPE=CHECKBOX ID=onselect>
<LABEL FOR=onselect>Select</LABEL><BR>
<INPUT TYPE=CHECKBOX ID=onselectstart>
<LABEL FOR=onselectstart>SelectStart</LABEL><BR>
<INPUT TYPE=CHECKBOX ID=onclick>
<LABEL FOR=onclick>Click</LABEL><BR>
<INPUT TYPE=CHECKBOX ID=ondblclick>
<LABEL FOR=ondblclick>DblClick</LABEL><BR>
<INPUT TYPE=CHECKBOX ID=onfocus>
<LABEL FOR=onfocus>Focus</LABEL><BR>
<INPUT TYPE=CHECKBOX ID=onblur>
<LABEL FOR=onblur>Blur</LABEL><BR>
<INPUT TYPE=CHECKBOX ID=onchange>
<LABEL FOR=onchange>Change</LABEL><BR>
<INPUT TYPE=CHECKBOX ID=ondragstart>
<LABEL FOR=ondragstart>DragStart</LABEL>
</TD></TR>
</TABLE>
<!-- Текстовая область для вывода последовательности событий -->
<TEXTAREA ID="txtEvents" STYLE="width:95%" ROWS=14>
</TEXTAREA>
</FORM>
</BODY>
</HTML>

Вы можете поэкспериментировать с данным кодом в любом документе, скопировав его с компакт-диска на жесткий диск. Замените файл sample.htm на любой файл по вашему выбору. Вы можете также запустить пример на компакт-диске, открыв файл tutor.htm, который использует файлы sample.htm и events.htm.



Event Broadcaster

Модель событий динамического HTML в целом ограничена отношениями "один-к-одному" между событием и обработчиком события. Однако возможны случаи, когда потребуется связать несколько действий с одним событием. Такая связь может быть реализована путем написания процедуры для события, которая вызывает каждое действие последовательно, или данный процесс целиком может быть автоматизирован путем использования указателей функций JavaScript.

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

На основе данного кода вы можете создать повторно используемые обработчики событий, которые легко могут быть вставлены в любую Web-страницу без изменения остального кода. Данный метод использует модель регистрации для обеспечения функциональности регистрации элемента с определенным действием. Реестр заменяет разработчика, который непосредственно работает с кодом события.

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

Приведенный ниже код представляет целиком весь код реестра Event Broadcaster. Такой код может быть написан только на языках, поддерживающих динамическое создание функций - поэтому данная функциональная возможность не может быть реализована в VBScript. Однако данный код не запрещает указать действие и зарегистрировать обработчик событий, написанный на VBScript.


<SCRIPT LANGUAGE="JavaScript">
// Код Event Broadcaster Registry
// Данный код связывает многочисленные обработчики событий с одним // событием.
function runHandler(eventName, eventSrc) {
// Это общий обработчик событий. // Для всех событий данная функция проверяет условие и // запускает соответствующий код.
var src = event.srcElement;
// Сначала проверяется srcElement.
for (var intLoop = 0;
intLoop < eventSrc.manager[eventName].length; intLoop++)
if (eventSrc.manager[eventName][intLoop].condition(src))
eventSrc.manager[eventName][intLoop].doAction(src);
src = src.parentElement;
// Переход по дереву иерархии и остановка на элементе, который // является источником события.
// Для документа tagName равно null; переход по всему дереву.
var top = (this.tagName == null) ? "HTML" : this.tagName;
while (top != src.tagName) {
for (var intLoop = 0;
intLoop < eventSrc.manager[eventName].length;
intLoop++)
if (eventSrc.manager[eventName][intLoop].condition(src) &&
eventSrc.manager[eventName][intLoop].doTree)
eventSrc.manager[eventName][intLoop].doAction(src);
src = src.parentElement;
}
}
function setupHandler(eventName, eventSrc) {
// Создание нового обработчика функций для события.
eventSrc[eventName] =
new Function("runHandler('" + eventName + "', this);");
}
function alwaysTrue() {
// Используйте данную функцию, если не собираетесь проверять условия.
return true;
}
function register(eventName, action) {
// Это общая процедура регистрации события.
// Параметры (в соответствующем порядке):
// eventName - Имя события, с которым будет установлена связь
// action - Код, который должен быть запущен при
// возникновении события
// condition (optional) - Условие для запуска действия;
// по умолчанию равно true
// doTree (optional) - Определяет необходимость перехода по
// всем узлам дерева
// по умолчанию равно false
// eventSrc (optional) - Элемент, с которым связано событие;
// По умолчанию равно document
// Определяет источник события.
var eventSrc = (null != arguments[4]) ?
document.all[arguments[4]] : document;
// Проверяет существование диспетчера событий на объекте.
if (null == eventSrc.manager)
eventSrc.manager = new Object;
// Проверяет наличие диспетчера событий для определенного события.
if (null == eventSrc.manager[eventName]) {
eventSrc.manager[eventName] = new Object;
eventSrc.manager[eventName].length = 0;
setupHandler(eventName, eventSrc);
}
// Добавляет обработчик событий.
var ct = eventSrc.manager[eventName].length++;
eventSrc.manager[eventName][ct] = new Object;
eventSrc.manager[eventName][ct].doAction = action;
// Проверяет, было ли указано условие. Если условие не указано, // то всегда возвращает true. eventSrc.manager[eventName][ct].condition =
(null != arguments[2]) ? arguments[2] : alwaysTrue;
// Проверяет переход по дереву. По умолчанию // равно false.
eventSrc.manager[eventName][ct].doTree =
(null != arguments[3]) ? arguments[3] : false;
}
function hookupEvents() {
var bindings = document.all.tags("BINDEVENT");
for (var intLoop = 0; intLoop < bindings.length; intLoop++) {
var bind = bindings[intLoop];
if ((null != bind.getAttribute("event")) &&
(null != bind.getAttribute("action"))) {
var bEvent = bind.getAttribute("event");
var bAction = new Function("return " +
bind.getAttribute("action") +
"(arguments[0])");
var bCondition =
(null == bind.getAttribute("condition")) ?
null :
new Function("return " +
bind.getAttribute("condition") +
"(arguments[0])");
var bTree = ("walk" == bind.getAttribute("tree"));
var bSrc = bind.getAttribute("for");
register(bEvent, bAction, bCondition, bTree, bSrc);
}
}
}
window.onload = hookupEvents;
</SCRIPT>

В данном коде использованы элементы динамического HTML и JavaScript. Все методы, которые были использованы в данном примере, обсуждаются в следующих главах. Например, HTML не определяет или не поддерживает тег <BINDEVENT>. Напротив, динамический HTML представляет нераспознаваемые элементы в объектной модели. Вы можете использовать данный элемент для связи информации и расширения сценариев без изменения кода.

Для использования данного кода напишите вызывающую его функцию и опишите ее связь с событием определенного объекта на странице.

Приведенный ниже код демонстрирует, как динамические эффекты могут быть добавлены и зарегистрированы в приведенном выше сервисе связывания. Динамическое изменение стиля элемента обсуждается в главе 11.


<SCRIPT LANGUAGE="JavaScript">
// Эффект динамического стиля mouseover
function swapEffects(src) {
// Поменять эффект с элементом className
if (null != src.getAttribute("effect")) {
var tempClass = src.className;
src.className = src.getAttribute("effect");
src.setAttribute("effect", tempClass);
}
}
function checkEffect(src) {
// Условие, которое следует проверить перед заменой эффекта return
return (src.getAttribute("effect") != null);
}
</SCRIPT>

Данный сценарий определяет действие и условие для обмена эффектов с атрибутом класса. Приведенный ниже код HTML связывает данный код с событиями onmouseover и onmouseout документа:


<BINDEVENT event="onmouseover" action="swapEffects" condition="checkEffect" tree="walk">
<BINDEVENT event="onmouseout" action="swapEffects" condition="checkEffect" tree="walk">

Индивидуальное связывание событий является мощным механизмом в том смысле, что автору не требуется знать как происходит захват кода, он может просто вставить код в свою страницу. С помощью легко используемого HTML данный код может быть связан с любым событием любого объекта. Действительная мощь этой модели раскрывается, когда пользователь пытается связать другое действие с событиями onmouseover или onmouseout. Обычно это требует написания индивидуальных обработчиков событий оnmousemove или onmouseout для вызова последовательности различных действий. Для использования продемонстрированного метода необходимо только вставить новую выполняемую функцию в документ и связать ее с событием, используя другой тег <BINDEVENT>. Код реестра автоматически управляет правильными наборами обработчиков событий и гарантирует, что они запускаются для каждого события.

Тег <BINDEVENT> поддерживает дополнительный атрибут for для связи события непосредственно с определенным элементом. По умолчанию событие присоединяется к документу. Атрибут for использует идентификатор (ID) элемента, с которым связывается событие.