Создание и вызов событий
Содержание:
- Отличия IE8-
- javascript onclick без клика
- event.defaultPrevented
- Событие: pointercancel
- Event Bubbling or Event Capturing?
- Элементы, связанные с событием
- Захват указателя
- Пример:Onclick В JavaScript, используя метод addEventListener()
- Погружение
- Подписка на событие через код HTML
- JavaScript
- Как передать данные в другой тег по id при onclick
- Подписка на событие через код JavaScript с помощью свойства
- Координаты мыши: clientX(Y)/pageX(Y)
- Итого
- Итого
Отличия IE8-
Чтобы было проще ориентироваться, я собрал отличия IE8-, которые имеют отношение ко всплытию, в одну секцию.
Их знание понадобится, если вы решите писать на чистом JS, без фреймворков и вам понадобится поддержка IE8-.
Нет свойства
Обратим внимание, что при назначении обработчика через у нас есть , поэтому , как правило, не нужно, а вот при назначении через обработчик не получает , так что текущий элемент, если нужен, можно будет взять лишь из замыкания.
Вместо в IE8- используется
Если мы пишем обработчик, который будет поддерживать и IE8- и современные браузеры, то можно начать его так:
Для остановки всплытия используется код .
Кросс-браузерно остановить всплытие можно так:
Далее в учебнике мы будем использовать стандартные свойства и вызовы, поскольку добавление этих строк, обеспечивающих совместимость – достаточно простая и очевидная задача. Кроме того, никто не мешает подключить полифил.
Ещё раз хотелось бы заметить – эти отличия нужно знать при написании JS-кода с поддержкой IE8- без фреймворков. Почти все JS-фреймворки обеспечивают кросс-браузерную поддержку , и .
javascript onclick без клика
javascript onclick без клика
но первое, что я подумал… вспомнил старый пошлый анекдот! дети, если вам нет 16, то закрываем страницу на этом месте!
Закрыли!? Я жду!
Теперь продолжим со взрослыми…
Встречается парочка на хате, а у парня был попугай! Девушка:
— я не могу заниматься этим, когда он смотрит…
Парень накинул тряпку на клетку.
И говорит попугаю! Будешь подсматривать — голову оторву!
Начали заниматься любовью!
— Давай я сверху, ты снизу!
— Давай!
…
— Давай ты сверху, я снизу!
— Давай!
…
— А теперь давай ты сверху, и я сверху!
Попугай:
— Пусть мне оторвут голову! Но это я должен увидеть!
event.defaultPrevented
Свойство установлено в , если действие по умолчанию было предотвращено, и , если нет.
Рассмотрим практическое применение этого свойства для улучшения архитектуры.
Помните, в главе Всплытие и погружение мы говорили о и упоминали, что останавливать «всплытие» – плохо?
Иногда вместо этого мы можем использовать , чтобы просигналить другим обработчикам, что событие обработано.
Давайте посмотрим практический пример.
По умолчанию браузер при событии (клик правой кнопкой мыши) показывает контекстное меню со стандартными опциями. Мы можем отменить событие по умолчанию и показать своё меню, как здесь:
Теперь в дополнение к этому контекстному меню реализуем контекстное меню для всего документа.
При правом клике должно показываться ближайшее контекстное меню.
Проблема заключается в том, что когда мы кликаем по элементу , то мы получаем два меню: контекстное меню для кнопки и (событие всплывает вверх) контекстное меню для документа.
Как это поправить? Одно из решений – это подумать: «Когда мы обрабатываем правый клик в обработчике на кнопке, остановим всплытие», и вызвать :
Теперь контекстное меню для кнопки работает как задумано. Но цена слишком высока. Мы навсегда запретили доступ к информации о правых кликах для любого внешнего кода, включая счётчики, которые могли бы собирать статистику, и т.п. Это слегка неразумно.
Альтернативным решением было бы проверить в обработчике , было ли отменено действие по умолчанию? Если да, тогда событие было обработано, и нам не нужно на него реагировать.
Сейчас всё работает правильно. Если у нас есть вложенные элементы и каждый из них имеет контекстное меню, то код также будет работать. Просто убедитесь, что проверяете в каждом обработчике .
event.stopPropagation() и event.preventDefault()
Как мы можем видеть, и (также известный как ) – это две разные функции. Они никак не связаны друг с другом.
Архитектура вложенных контекстных меню
Есть также несколько альтернативных путей, чтобы реализовать вложенные контекстные меню. Одним из них является единый глобальный объект с обработчиком и методами, позволяющими хранить в нём другие обработчики.
Объект будет перехватывать любой клик правой кнопкой мыши, просматривать сохранённые обработчики и запускать соответствующий.
Но при этом каждый фрагмент кода, которому требуется контекстное меню, должен знать об этом объекте и использовать его вместо собственного обработчика .
Событие: pointercancel
Событие происходит, когда текущее действие с указателем по какой-то причине прерывается, и события указателя больше не генерируются.
К таким причинам можно отнести:
- Указывающее устройство было физически выключено.
- Изменилась ориентация устройства (перевернули планшет).
- Браузер решил сам обработать действие, считая его жестом мыши, масштабированием и т.п.
Мы продемонстрируем на практическом примере, чтобы увидеть, как это влияет на нас.
Допустим, мы реализуем перетаскивание («drag-and-drop») для нашего мяча, как в начале статьи Drag’n’Drop с событиями мыши.
Вот последовательность действий пользователя и соответствующие события:
- Пользователь нажимает на изображении, чтобы начать перетаскивание
- Затем он перемещает указатель, двигая изображение
- И тут происходит сюрприз! Браузер имеет встроенную поддержку «Drag’n’Drop» для изображений, которая запускает и перехватывает процесс перетаскивания, генерируя при этом событие .
- Теперь браузер сам обрабатывает перетаскивание изображения. У пользователя есть возможность перетащить изображение мяча даже за пределы браузера, в свою почтовую программу или файловый менеджер.
- Событий для нас больше не генерируется.
Таким образом, браузер «перехватывает» действие: в начале переноса drag-and-drop запускается событие , и после этого события больше не генерируются.
Вот демо drag’n’drop с записью событий указателя (только , и ) в :
Мы бы хотели реализовать перетаскивание самостоятельно, поэтому давайте скажем браузеру не перехватывать его.
Предотвращайте действие браузера по умолчанию, чтобы избежать .
Нужно сделать две вещи:
- Предотвратить запуск встроенного drag’n’drop
- Мы можем сделать это, задав , как описано в статье Drag’n’Drop с событиями мыши.
- Это работает для событий мыши.
- Для устройств с сенсорным экраном существуют другие действия браузера, связанные с касаниями, кроме drag’n’drop. Чтобы с ними не возникало проблем:
- Мы можем предотвратить их, добавив в CSS свойство .
- Затем наш код начнёт корректно работать на устройствах с сенсорным экраном
После того, как мы это сделаем, события будут работать как и ожидается, браузер не будет перехватывать процесс и не будет вызывать событие .
В данном демо произведены нужные действия:
Как вы можете видеть, событие больше не срабатывает.
Теперь мы можем добавить код для перемещения мяча и наш drag’n’drop будет работать и для мыши и для устройств с сенсорным экраном.
Event Bubbling or Event Capturing?
There are two ways of event propagation in the HTML DOM, bubbling and capturing.
Event propagation is a way of defining the element order when an event occurs.
If you have a <p> element inside a <div> element, and the user clicks on the <p> element, which element’s
«click» event should be handled first?
In bubbling the inner most element’s event is handled first and then the outer:
the <p> element’s click event is handled first, then the <div> element’s click event.
In capturing the outer most element’s event is handled first and then the inner:
the <div> element’s click event will be handled first, then the <p> element’s click event.
With the addEventListener() method you can specify the propagation type by using the «useCapture» parameter:
addEventListener(event, function, useCapture);
The default value is false, which will use the bubbling propagation, when the value is set to true, the event uses the capturing propagation.
Example
document.getElementById(«myP»).addEventListener(«click», myFunction, true);
document.getElementById(«myDiv»).addEventListener(«click», myFunction, true);
Элементы, связанные с событием
Чаще всего нужно узнать, на каком элементе сработало событие.
Например, мы поймали на внешнем ‘е и хотим знать, на каком из внутренних элементов оно на самом деле произошло.
В Internet Explorer у объекта для этого есть свойство , в остальных браузерах, работающих по рекомендациям W3C, для этого используется .
Вот пример использования этого свойства. Обработчик стоит только на внешнем диве, но благодаря выводит по клику класс исходного элемента.
1
2
3
Ссылка
<div class="d1" onclick="*!*t=event.target||event.srcElement; alert(t.className)*/!*" > <span class="number">1</span> <div class="d2"> <span class="number">2</span> <div class="d3"> <span class="number">3</span> </div> <a class="d2a" href="javascript:void(0)">Ссылка</a> </div> </div>
Javascript-обработчик в примере висит только на внешнем диве и выглядит примерно так:
function(event) { // получить объект событие. // вместо event лучше писать window.event event = event || window.event // кросс-браузерно получить target var t = event.target || event.srcElement alert(t.className) }
Для событий и предусмотрен способ получить как элемент на который курсор мыши перешел, так и элемент, с которого он перешел.
Эти свойства — в W3C, и в Internet Explorer.
// Обработчик для mouseover function mouseoverHandler(event) { event = event || window.event var relatedTarget = event.relatedTarget || event.fromElement // для mouseover // relatedTarget - элемент, *!*с которого*/!* пришел курсор мыши } // Обработчик для mouseout function mouseoutHandler(event) { event = event || window.event var relTarg = event.relatedTarget || event.toElement // для mouseout // relatedTarget - элемент, *!*на который*/!* перешел курсор мыши }
Свойство дополняет . В нем всегда находится информация о втором элементе, участвовавшем в событии.
Поэтому его можно получить для IE, взяв то свойство из , которое не равно :
if (!e.relatedTarget && e.fromElement) { e.relatedTarget = (e.fromElement==e.target) ? e.toElement : e.fromElement }
При всплытии — событие по очереди вызвает обработчики на элементе-триггере и дальше, вверх по документу.
По мере всплытия, текущим элементом каждый раз становится новый. Иначе говоря. текущий элемент — это тот, к которому в данный момент «доплыло» событие.
Стандартный способ получить текущий элемент — использовать переменную .
Например, при клике на внутренний , код в этом примере последовательно отмечает элементы, на которых регистрируется всплывающее событие:
1
2
3
<div class="d1" onclick="highlightMe(this)">1 <div class="d2" onclick="highlightMe(this)">2 <div class="d3" onclick="highlightMe(this)">3</div> </div> </div>
Захват указателя
Захват указателя – особая возможность событий указателя.
Общая идея очень проста, но поначалу может показаться странной, так как для других событий ничего подобного просто нет.
Основной метод:
elem.setPointerCapture(pointerId) – привязывает события с данным pointerId к elem. После такого вызова все события указателя с таким pointerId будут иметь elem в качестве целевого элемента (как будто произошли над elem), вне зависимости от того, где в документе они произошли.
Другими словами, меняет всех дальнейших событий с данным на .
Эта привязка отменяется:
- автоматически, при возникновении события или ,
- автоматически, если удаляется из документа,
- при вызове .
Захват указателя используется для упрощения операций с переносом (drag’n’drop) элементов.
В качестве примера давайте вспомним реализацию слайдера из статьи Drag’n’Drop с событиями мыши.
Мы делаем элемент для слайдера – полоску с «ползунком» () внутри.
Затем он работает так:
- Пользователь сначала нажимает на ползунок – срабатывает .
- Затем двигает указателем его – срабатывает , и мы передвигаем ползунок вместе с ним.
Так что для полного отслеживания перемещения указателя, включая ниже и выше ползунка, нам пришлось поставить обработчик на весь документ .
Такое решение выглядит слегка «грязным». Одна из проблем – это то, что движения указателя по документу могут вызвать сторонние эффекты, заставить сработать другие обработчики, не имеющие отношения к слайдеру.
Захват указателя позволяет привязать к и избежать любых подобных проблем:
- Мы можем вызывать в обработчике ,
- Тогда дальнейшие события указателя до будут привязаны к .
- Затем, когда произойдёт (передвижение завершено), привязка будет автоматически удалена, нам об этом не нужно беспокоиться.
Так что, даже если пользователь будет двигать указателем по всему документу, обработчики событий будут вызваны на . Причём все свойства объекта события, такие как , будут корректны – захват указателя влияет только на .
Вот основной код:
Полное демо:
Таким образом, мы имеем два бонуса:
- Код становится чище, поскольку нам больше не нужно добавлять/удалять обработчики для всего документа. Удаление привязки происходит автоматически.
- Если в документе есть какие-то другие обработчики , то они не будут нечаянно вызваны, пока пользователь находится в процессе перетаскивания слайдера.
Существует два связанных с захватом события:
- срабатывает, когда элемент использует для включения захвата.
- срабатывает при освобождении от захвата: явно с помощью или автоматически, когда происходит событие /.
Пример:Onclick В JavaScript, используя метод addEventListener()
И последний элемент теории Onclick — использование метода addEventListener
Нам опять понадобится кнопка
<button id=»onclick_v_addEventListener»>Это второй способ реализации Onclick в JavaScript</button>
Опять применяем querySelector — обращаемся к нашей кнопке, добавляем метод addEventListener, во внутрь помещаем событие click И второй параметр — это функция myFoo.
document.querySelector(«#onclick_v_addEventListener») .addEventListener(«click», myFoo);
Далее нам понадобится функция:
function myFoo() { alert(«Это третий способ реализации Onclick в JavaScript через addEventListener и вывод через alert»); }
Соберем весь код вместе:
<button id=»onclick_v_addEventListener»>Это третий способ реализации Onclick в JavaScript</button>
<script>
document.querySelector(«#onclick_v_addEventListener») .addEventListener(«click», myFoo);
function myFoo()
{
alert(«Это третий способ реализации Onclick в JavaScript через addEventListener и вывод через alert»);
}
</script>
Результат:
Это третий способ реализации Onclick в JavaScript
Погружение
Существует ещё одна фаза из жизненного цикла события – «погружение» (иногда её называют «перехват»). Она очень редко используется в реальном коде, однако тоже может быть полезной.
Стандарт DOM Events описывает 3 фазы прохода события:
- Фаза погружения (capturing phase) – событие сначала идёт сверху вниз.
- Фаза цели (target phase) – событие достигло целевого(исходного) элемента.
- Фаза всплытия (bubbling stage) – событие начинает всплывать.
Картинка из спецификации демонстрирует, как это работает при клике по ячейке , расположенной внутри таблицы:
То есть при клике на событие путешествует по цепочке родителей сначала вниз к элементу (погружается), затем оно достигает целевой элемент (фаза цели), а потом идёт наверх (всплытие), вызывая по пути обработчики.
Ранее мы говорили только о всплытии, потому что другие стадии, как правило, не используются и проходят незаметно для нас.
Обработчики, добавленные через -свойство или через HTML-атрибуты, или через с двумя аргументами, ничего не знают о фазе погружения, а работают только на 2-ой и 3-ей фазах.
Чтобы поймать событие на стадии погружения, нужно использовать третий аргумент вот так:
Существуют два варианта значений опции :
- Если аргумент (по умолчанию), то событие будет поймано при всплытии.
- Если аргумент , то событие будет перехвачено при погружении.
Обратите внимание, что хоть и формально существует 3 фазы, 2-ую фазу («фазу цели»: событие достигло элемента) нельзя обработать отдельно, при её достижении вызываются все обработчики: и на всплытие, и на погружение. Давайте посмотрим и всплытие и погружение в действии:
Давайте посмотрим и всплытие и погружение в действии:
Здесь обработчики навешиваются на каждый элемент в документе, чтобы увидеть в каком порядке они вызываются по мере прохода события.
Если вы кликните по , то последовательность следующая:
- → → → (фаза погружения, первый обработчик)
- (фаза цели, срабатывают обработчики, установленные и на погружение и на всплытие, так что выведется два раза)
- → → → (фаза всплытия, второй обработчик)
Существует свойство , содержащее номер фазы, на которой событие было поймано. Но оно используется редко, мы обычно и так знаем об этом в обработчике.
Чтобы убрать обработчик , нужна та же фаза
Если мы добавили обработчик вот так , то мы должны передать то же значение аргумента в , когда снимаем обработчик.
На каждой фазе разные обработчики на одном элементе срабатывают в порядке назначения
Если у нас несколько обработчиков одного события, назначенных на один элемент, в рамках одной фазы, то их порядок срабатывания – тот же, в котором они установлены:
Подписка на событие через код HTML
Данный способ основывается на использовании атрибута, который имеет вид , где — это имя определённого события.
Основные действия: добавить к элементу определённый атрибут (например: — где: означает событие, а — вид события) со значением, содержащим оператор или функцию. Данный оператор или функция будет выполняться при наступлении этого события у элемента.
Например, добавить к кнопке событие , при наступлении которого будет выводиться сообщение с помощью метода :
<button onclick="alert('Событие click')" vаlue="Демонстрация события click">
Если в обработчике события надо выполнить некоторый код, то необходимо использовать функцию.
Например, выполним вышеприведённый пример с использованием функции:
<button onclick="myFunction()" value="Демонстрация события click"> <script> //функция, которая будет вызываться при наступлении события click у указанного элемента function myFunction() { alert('Событие click'); } </script>
Например, добавить к кнопке событие , при наступлении которого выполняется указанная функция:
<button onclick="countElements()" value="Количество элементов на странице"> <script> //функция, которая будет вызываться при наступлении события click у указанного элемента function countElements() { var count = document.getElementsByTagName("*").length; alert("Количество элементов на странице:" + count.toString()); } </script>
Данный вариант подписки на событие использовать не рекомендуется, т.к. он не только загромождает код HTML, но и имеет ограничения связанные с использованием объекта , ключевого слово и др.
JavaScript
JS Array
concat()
constructor
copyWithin()
entries()
every()
fill()
filter()
find()
findIndex()
forEach()
from()
includes()
indexOf()
isArray()
join()
keys()
length
lastIndexOf()
map()
pop()
prototype
push()
reduce()
reduceRight()
reverse()
shift()
slice()
some()
sort()
splice()
toString()
unshift()
valueOf()
JS Boolean
constructor
prototype
toString()
valueOf()
JS Classes
constructor()
extends
static
super
JS Date
constructor
getDate()
getDay()
getFullYear()
getHours()
getMilliseconds()
getMinutes()
getMonth()
getSeconds()
getTime()
getTimezoneOffset()
getUTCDate()
getUTCDay()
getUTCFullYear()
getUTCHours()
getUTCMilliseconds()
getUTCMinutes()
getUTCMonth()
getUTCSeconds()
now()
parse()
prototype
setDate()
setFullYear()
setHours()
setMilliseconds()
setMinutes()
setMonth()
setSeconds()
setTime()
setUTCDate()
setUTCFullYear()
setUTCHours()
setUTCMilliseconds()
setUTCMinutes()
setUTCMonth()
setUTCSeconds()
toDateString()
toISOString()
toJSON()
toLocaleDateString()
toLocaleTimeString()
toLocaleString()
toString()
toTimeString()
toUTCString()
UTC()
valueOf()
JS Error
name
message
JS Global
decodeURI()
decodeURIComponent()
encodeURI()
encodeURIComponent()
escape()
eval()
Infinity
isFinite()
isNaN()
NaN
Number()
parseFloat()
parseInt()
String()
undefined
unescape()
JS JSON
parse()
stringify()
JS Math
abs()
acos()
acosh()
asin()
asinh()
atan()
atan2()
atanh()
cbrt()
ceil()
clz32()
cos()
cosh()
E
exp()
expm1()
floor()
fround()
LN2
LN10
log()
log10()
log1p()
log2()
LOG2E
LOG10E
max()
min()
PI
pow()
random()
round()
sign()
sin()
sqrt()
SQRT1_2
SQRT2
tan()
tanh()
trunc()
JS Number
constructor
isFinite()
isInteger()
isNaN()
isSafeInteger()
MAX_VALUE
MIN_VALUE
NEGATIVE_INFINITY
NaN
POSITIVE_INFINITY
prototype
toExponential()
toFixed()
toLocaleString()
toPrecision()
toString()
valueOf()
JS OperatorsJS RegExp
constructor
compile()
exec()
g
global
i
ignoreCase
lastIndex
m
multiline
n+
n*
n?
n{X}
n{X,Y}
n{X,}
n$
^n
?=n
?!n
source
test()
toString()
(x|y)
.
\w
\W
\d
\D
\s
\S
\b
\B
\0
\n
\f
\r
\t
\v
\xxx
\xdd
\uxxxx
JS Statements
break
class
continue
debugger
do…while
for
for…in
for…of
function
if…else
return
switch
throw
try…catch
var
while
JS String
charAt()
charCodeAt()
concat()
constructor
endsWith()
fromCharCode()
includes()
indexOf()
lastIndexOf()
length
localeCompare()
match()
prototype
repeat()
replace()
search()
slice()
split()
startsWith()
substr()
substring()
toLocaleLowerCase()
toLocaleUpperCase()
toLowerCase()
toString()
toUpperCase()
trim()
valueOf()
Как передать данные в другой тег по id при onclick
уникальным идентификаторомid<div id=»demo»></div>
Далее нам понадобится скрипт, который по нажатию, отправит какие-то данные в этот див:
<button onclick=»getElementById(‘demo’).innerHTML = Date()»>Сколько времени!?</button>
Сколько времени!?тегу
Как вызвать функцию по клику, как мы уже раньше говорили, что click можно вызвать
1). В первом случае меняем слово alert на название функции, а в скобках идущих после alert убираем содержимое…
В функции прописываем что-то…
<script> function my_super_foo(){alert(«Вызов функции в теге… по клику»); }</script>
<button onclick=»my_super_foo()»>Вызов функции в теге… по клику</button>
Результат вызова функции из тега
Вызов функции в теге… по клику2). Второй способ… идем во встрой способ… там даже и переделывать ничего не нужно… заменяем только само действие в внутри функции priner_id .innerHTML =»НОВЫЙ ТЕКСТ»; — готовый способ вызова функции по клику…
3). Третий способ аналогичен второму… копируем все, что описано в третье пункте, заменяем внутри функции на ваше действие…
В качестве примера рекомендую — страницу с кнопками — все события производится именно кнопками, на которых повешено событие onclick.
1). Как повесить на одну кнопку сразу две функции!? Или три!? Или четыре… так можно продолжать до бесконечности:
Если говорить о двух событиях на onclick, то во всех , кроме первого(в теге) — этот вопрос кажется немного странным! Почему!? Просто во внутрь функции ставишь не одно событие, а столько сколько захочешь!
Если говорить об onclick два события в теге, то внутри onclick прописываем стандартные действия как в js
<button onclick=»getElementById(‘demo’).innerHTML = Date();alert(‘Щелчок мыши!’)»>Два события.</button>
<kod id=»demo»></kod>
Два события.
2). Если мы возьмем и сделаем функцию, обрабатывающую нажатие на кнопку…, то там тоже нет никакой проблемы повесить на кнопку два, три, пять, 100 функций!
<button id=»new_id»>Две функции onclick на одну кнопку js</button>
<script>
new_id .addEventListener(«click», myFoo);
function myFoo()
{
alert(«одна функция onclick на одну кнопку js»);
alert(«Две функции onclick на одну кнопку js»);
alert(«Три функции onclick на одну кнопку js»);
}
</script>
Две функции onclick на одну кнопку js
Если , например нужно изменить где-то цвет, то можно посмотреть пример с помощью onclick
Код:
<button onclick=»getElementById(‘rezult’).setAttribute(‘style’, ‘color: red;’);»>Изменить цвет</button>
<div id=»rezult»>Здесь текст, который будет менять при нажатии</div>
Результат:
Изменить цвет
Здесь текст, который будет менять при нажатии
4.
Например, когда надо много событий навесить в onclick, то можно навесить на onclick только функцию, а в функции написать функцию, которая и будет выполнять все, что нужно при нажатии на кнопку…
Далее изменение текста и одновременное изменение цвета.
Код:
далее скрипт, либо можно выделить в отдельный файл скрипта…
<script> function foo() {
document.getElementById(«rezult_1»).innerHTML = «привет»;
document.getElementById(«rezult_1»).setAttribute(«style», «color: red» );
}
</script>
Результат:
Нажми здесь
Здесь текст, который будет менять при нажатии
Подписка на событие через код JavaScript с помощью свойства
Этот способ подписки на событие осуществляется через код JavaScript с помощью задания элементу свойства . Основной принцип данного метода заключается в следующем:
- Найти элемент (объект) в DOM-дереве, на событие которого Вы хотите подписаться.
- Добавить найденному объекту свойство, которое должно иметь следующий вид:
, где — это имя определённого события.После этого необходимо данному свойству присвоить обработчик, т.е. безымянную или некоторую указанную функцию, которая будет выполняться при наступлении этого события.
Например, подписаться на событие элемента, имеющего . При наступлении этого события () выполнить его обработку с помощью безымянной функции:
<button id="myBtn" value="Демонстрация события click"> <script> //в качестве обработчика события будем использовать безымянную функцию: document.getElementById("myID").onclick = function { alert("Событие click"); } </script>
Например, добавить к кнопке, имеющей событие , при наступлении которого выполняется указанная функция:
//Найти элемент на событие, которого Вы хотите подписаться var myButton = document.getElementById("myButton"); //добавить к объекту свойство, имеющее имя on //при наступлении события click выполняется функция myFunction myButton.onclick = myFunction; //функция myFunction function myFunction() { //код функции //... }
Если событие задаётся через атрибут, то браузер, читая код HTML, создаёт соответствующее свойство автоматически. Т.е. браузер работает с событиями только с помощью соответствующих свойств объекта (элемента).
Если Вы подпишитесь на событие различными способами, т.е. через атрибут и с помощью свойства, то браузер в этом случае будет использовать только вариант реализации события, выполненный с помощью свойства.
Подписываться на события лучше только с помощью соответствующих свойств объекта (элемента), использовать атрибуты для этих целей не рекомендуется.
Координаты мыши: clientX(Y)/pageX(Y)
При обработке событий, связанных с мышью, нужен кроссбраузерный способ получения координат курсора из события в обработчике.
Координаты курсора мыши относительно окна находятся в стандартных свойствах . Они одинаково поддерживается всеми браузерами.
Если у вас есть окно 500×500, и мышь находится в центре, то и будут оба равны 250. Если вы затем проскроллируете документ вниз, налево или вверх, не двигая курсор — значения не изменятся, так как отсчитываются относительно окна, а не документа.
Как правило, при обработке события нужна позиция мыши относительно документа, учитывающая прокрутку. Стандарт W3C предоставляет для этого свойство .
Если у вас есть окно 500×500, и мышь находится в центре, то и будут оба равны 250. Если вы затем проскроллируете на 250 пикселей вниз, станет равным 750.
Таким образом содержат координаты, на каком месте документа произошло событие, учитывая все прокрутки.
Свойства поддерживаются всеми браузерами, кроме Internet Explorer.
В IE их можно получить из , прибавив к ним .
Обычно оно находится в <body>: , но это не всегда так. Например, при выборе Strict DTD оно высчитывается для <html>: . Кроме того, тэга <body> может просто не быть в документе.
Поэтому мы сначала возьмем (если есть), затем проверим . Если нет ни того, ни того, то 0.
var html = document.documentElement var body = document.body e.pageX = e.clientX + (html && html.scrollLeft || body && body.scrollLeft || 0)
Кроме того, в IE может быть немного сдвинут с позиции 0,0. Значение сдвига находится в , и его также необходимо учесть.
Этот код позволяет надежно получить для IE, в котором его изначально нет:
if (e.pageX == null && e.clientX != null ) { var html = document.documentElement var body = document.body e.pageX = e.clientX + (html && html.scrollLeft || body && body.scrollLeft || 0) - (html.clientLeft || 0) e.pageY = e.clientY + (html && html.scrollTop || body && body.scrollTop || 0) - (html.clientTop || 0) }
Этот обработчик обновляет координаты мыши относительно документа.
function mouseShowHandler(e){ e = e || window.event if (e.pageX == null && e.clientX != null ) { var html = document.documentElement var body = document.body e.pageX = e.clientX + (html && html.scrollLeft || body && body.scrollLeft || 0) - (html.clientLeft || 0) e.pageY = e.clientY + (html && html.scrollTop || body && body.scrollTop || 0) - (html.clientTop || 0) } document.getElementById('mouseX').value = e.pageX document.getElementById('mouseY').value = e.pageY }
Координата X:
Координата Y:
Итого
Делегирование событий – это здорово! Пожалуй, это один из самых полезных приёмов для работы с DOM.
Он часто используется, если есть много элементов, обработка которых очень схожа, но не только для этого.
Алгоритм:
- Вешаем обработчик на контейнер.
- В обработчике проверяем исходный элемент .
- Если событие произошло внутри нужного нам элемента, то обрабатываем его.
Зачем использовать:
- Упрощает процесс инициализации и экономит память: не нужно вешать много обработчиков.
- Меньше кода: при добавлении и удалении элементов не нужно ставить или снимать обработчики.
- Удобство изменений DOM: можно массово добавлять или удалять элементы путём изменения и ему подобных.
Конечно, у делегирования событий есть свои ограничения:
Во-первых, событие должно всплывать. Некоторые события этого не делают. Также, низкоуровневые обработчики не должны вызывать .
Во-вторых, делегирование создаёт дополнительную нагрузку на браузер, ведь обработчик запускается, когда событие происходит в любом месте контейнера, не обязательно на элементах, которые нам интересны
Но обычно эта нагрузка настолько пустяковая, что её даже не стоит принимать во внимание.
Итого
При наступлении события – самый глубоко вложенный элемент, на котором оно произошло, помечается как «целевой» ().
- Затем событие сначала двигается вниз от корня документа к , по пути вызывая обработчики, поставленные через , где – это сокращение для .
- Далее обработчики вызываются на целевом элементе.
- Далее событие двигается от вверх к корню документа, по пути вызывая обработчики, поставленные через и без третьего аргумента или с третьим аргументом равным .
Каждый обработчик имеет доступ к свойствам события :
- – самый глубокий элемент, на котором произошло событие.
- (=) – элемент, на котором в данный момент сработал обработчик (тот, на котором «висит» конкретный обработчик)
- – на какой фазе он сработал (погружение=1, фаза цели=2, всплытие=3).
Любой обработчик может остановить событие вызовом , но делать это не рекомендуется, так как в дальнейшем это событие может понадобиться, иногда для самых неожиданных вещей.
В современной разработке стадия погружения используется очень редко, обычно события обрабатываются во время всплытия. И в этом есть логика.
В реальном мире, когда происходит чрезвычайная ситуация, местные службы реагируют первыми. Они знают лучше всех местность, в которой это произошло, и другие детали. Вышестоящие инстанции подключаются уже после этого и при необходимости.
Тоже самое справедливо для обработчиков событий. Код, который «навесил» обработчик на конкретный элемент, знает максимум деталей об элементе и его предназначении. Например, обработчик на определённом скорее всего подходит только для этого конкретного , он знает все о нём, поэтому он должен отработать первым. Далее имеет смысл передать обработку события родителю – он тоже понимает, что происходит, но уже менее детально, далее – выше, и так далее, до самого объекта , обработчик на котором реализовывает самую общую функциональность уровня документа.
Всплытие и погружение являются основой для «делегирования событий» – очень мощного приёма обработки событий. Его мы изучим в следующей главе.