Обработка событий
Дата публикации: 13.07.2011
Одной из наиболее часто используемых функций Javascript является обработка событий. Давай посмотрим, как мобильные браузеры справляются с этой задачей.
Управление событиями
Мы можем указать в скриптах обработку событий при помощи следующих методов (в таблице 8.22 можешь посмотреть, какие браузеры поддерживают эти методы):
- использование HTML атрибутов (вроде onclick=»alert(‘sample’)»);
- использование JavaScript свойства объекта (element.onclick = function(){});
- использование DOM-метода addEventListener.
В Internet Explorer вместо метода DOM addEventListener, Microsoft использует свойство элемента attachEvent.
Браузер/ Платформа | атрибут HTML | свойство Object | addEventListener |
---|---|---|---|
Safari | Да | Да | Да |
браузер Android | Да | Да | Да |
Symbian/S60 | Да | Да | Да |
Nokia Series 40 | Да | Нет до версии 4.6 | Нет до версии 4.6 |
webOS | Да | Да | Да |
BlackBerry | Да | Нет до версии 4.6 | Нет |
NetFront | Да | Да | Нет |
Internet Explorer | Да | Нет | Нет |
Motorola Internet Browser | Да | Нет | Нет |
Opera Mobile | Да | Да | Да |
Opera Mini | Да, с обратной передачей серверу |
События load и unload
Хорошо известное событие <onload> доступно для любого HTML элемента, но лучше всего его применять в элементе <body>. Мы протестируем совместимость этого события с различными типами элементов.
Событие <onunload> уже не так популярно. В теории это событие тоже должно работать для каждого элемента, но и в этом случае его лучше всего применять к элементу <body> (document object), чтобы обнаружить, когда пользователь уходит из нашего документа.
В современных браузерах событие <onunload> не работает так, как нам бы хотелось и было заменено нестандартным <onbeforeunload>. Событие <onbeforeunload> используется для предупреждения пользователя о незавершенной операции или не сохраненных изменениях, данные о которых могут быть потеряны при переходе на URL или предыдущую страницу. Для подтверждения используется, как правило, диалоговое окно.
В таблице 8.23 приведены данные о поддержке всех этих событий в разных браузерах.
Браузер/ Платформа | body (load) | body (unload) | body (beforeunload) | img (load) |
---|---|---|---|---|
Safari | Да | Да | Нет | Да |
браузер Android | Да | Да | Да | Да |
Symbian/S60 | Да | Да | Нет | Да |
Nokia Series 40 | Да | Нет | Нет | Нет, до 6-го выпуска |
webOS | Да | Да | Да | Да |
BlackBerry | Да | Нет | Нет | Да |
NetFront | Да | Да | Нет | Да |
Internet Explorer | Да | Да | Нет | Да |
Motorola Internet Browser | Нет | Нет | Нет | Нет |
Opera Mobile | Да | Нет | Нет | Да |
Opera Mini | Да | Нет | Нет | Нет |
Событие click
Событие <onclick> наиболее используемое событие в веб-разработке. Что же касается мобильных сайтов, то мы должны сначала протестировать его, чтобы понять, где его лучше всего использовать. Мы уже знаем, что есть браузеры с фокус-, курсор- и сенсорной навигацией. Браузеры с курсор-навигацией самые простые и удобные для применения событий клика: каждый раз, когда пользователь перемещает курсор и нажимает кнопку FIRE (или любую другую кнопку с аналогичным действием) — генерируется событие <onclick>. В браузерах с фокус-навигацией рекомендуется использовать событие <onclick> только для таких кликабельных элементов как ссылки или кнопки, потому что на других элементах (например, <div>, <p>, или <li>) не будет активен фокус.
На low-end устройствах input type=button нужно применять внимательно и осторожно. Некоторые устройства Series 40 требуют наличия для каждого поля тега <form>, а некоторые мобильные устройства Motorola вообще интерпретируют эту кнопку как submit и, получается, что при нажатии будут отправлять данные формы.
С сенсорными устройствами все просто: каждое касание (пальцем или стилусом) воспринимается как клик. В таблице 8.24 приведена информация, как разные браузеры поддерживают эти события.
Браузер/ Платформа | a | img | div | li |
---|---|---|---|---|
Safari | Да | Да | Да | Да |
браузер Android | Да | Да | Да | Да |
Symbian/S60 | Да, для сенсорной и курсор-навигациии | |||
Nokia Series 40 | Нет до 6-го выпуска | |||
webOS | Да | Да | Да | Да |
BlackBerry | Да | Нет | Нет до выпуска 4.6 | Нет |
NetFront | Да | Да | Да | Да |
Internet Explorer | Нет | Нет | Нет | Да |
Motorola Internet Browser | Да, все они преобразуются в кнопки | |||
Opera Mobile | Да | Да | Да | Да |
Opera Mini | Да | Да | Да | Да |
Если для нажатия по экрану пользователь использует палец (а не стилус), то ты должен помнить, что во время нажатия координаты клика могут измениться (все зависит от того, как пользователь нажимает по экрану пальцем) и большой точности ты тут не получишь. Делай площадь активной зоны побольше.
Двойное касание
Если тебе нужно на сенсорном устройстве обнаружить двойное касание, то не стоит использовать нестандартное событие <ondblclick> — работать в большинстве случаев не будет и, к тому же, сгенерирует событие <onclick>. Есть решение намного лучше (применимо и для несенсорных устройств) — нужно при помощи следующего кода сделать шаблон обнаружения двойного клика:
var doubletapDeltaTime_ = 700; var doubletap1Function_ = null; var doubletap2Function_ = null; var doubletapTimer = null; function tap(singleTapFunc, doubleTapFunc) { if (doubletapTimer==null) { // First tap, we wait X ms to the second tap doubletapTimer_ = setTimeout(doubletapTimeout_, doubletapDeltaTime_); doubletap1Function_ = singleTapFunc; doubletap2Function_ = doubleTapFunc; } else { // Second tap clearTimeout(doubletapTimer); doubletapTimer_ = null; doubletap2Function_(); } } function doubletapTimeout() { // Wait for second tap timeout doubletap1Function_(); doubleTapTimer_ = null; }
Можно использовать предыдущие библиотеки:
<img src="bigbutton.png" onclick="tap(tapOnce, tapTwice)" />
где tapOnce и tapTwice — 2 ранее объявленные функции.
Для неактивных элементов никакие события генерироваться не будут, а вот для активных элементов будут в таком порядке: <onmouseover>, <onmousedown>, <onmouseup>, <onclick>.
Как альтернативный вариант, мы можем это учитывать в JavaScript:
element.onclick = function() { tap( function() { // код для первого касания }, function() { // код для второго } ); }
Не забывай, что в некоторых тач-браузерах могут возникнуть проблемы с обработкой события касания и удерживания (или долгого касания), потому что браузер захватывает это события для вызова контекстного меню. Использовать такой прием можно только в текстовых блоках с отключенным user-selectable.
События тач и мультитач
В Safari начиная с iOS 2.0 есть поддержка мультитач. Пользователь может касаться экрана одновременно пятью пальцами (на iPad — 11 пальцев) и код JavaScript получит это событие. Для обнаружения мультитач не стоит использовать стандартное событие onclick. Вместо этого нужно заменить его одним из следующих нестандартных событий:
- ontouchstart;
- ontouchmove;
- ontouchend;
- ontouchcancel.
В браузере Android события тач поддерживаются, а вот поддержка мультитач уже зависит от аппаратной и программной составляющих.
Каждый раз при касании пользователем экрана выполняется ontouchstart; если пользователь подвигает одним или более пальцами — выполняется событие ontouchmove; когда пользователь убирает все пальцы с экрана — выполняется ontouchend. А как обстоят дела с событием ontouchcancel? Событие touch cancel срабатывает, если происходит какое-то внешнее событие с большим приоритетом чем наш сайт (входящий вызов, уведомление о нажатии, окно с предупреждением) отменяет саму операцию.
Если ты разрабатываешь игру, приложение для рисования или любой другой продукт, строящийся на сенсорном управлении, всегда помни о событии ontouchcancel: как только запустится это событие — все сенсорные действия должны быть приостановлены.
Четыре мультисенсорных события получают в качестве параметра один и тот же объект (TouchEvent). В нем содержится тач-массив, предоставляющий координаты каждого касания на странице; каждый элемент массива — объект со свойствами pageX и pageY. Если в устройстве не включен мультитач, то ты получишь массив только из одного элемента.
Пример типичного сценария:
<div ontouchstart="touchStart(event);" ontouchmove="touchMove(event);" ontouchend="touchEnd(event);" ontouchcancel="touchCancel(event);"> </div>
Тач-последовательность начинается с первого и заканчивается последним пальцем. Тач события будут относиться к тому же объекту, который получал и событие ontouchstart и не зависимо от того, какие координаты текущих касаний.
Первое, что мы можем сделать во всех событиях — отменить поведение по умолчанию в Safari для жеста пользователя. Делается это при помощи параметра TouchEvent:
event.preventDefault();
Объект TouchEvent поддерживает наборы массивов, указанные в таблице 8.25.
атрибут TouchEvent | Описание |
---|---|
touches | Все прикосновения на самом деле на экране |
targetTouches | Только прикосновения внутри целевого элемента события |
changedTouches | Только прикосновения, которые изменились с момента последнего вызова события (полезно в ontouchmove и ontouchend или для фильтрации только новых или удаленных касаний) |
Если пользователь уберет с экрана палец, то это действие будет доступно только в наборе changedTouches. В Android удаленное касание также доступно в наборе touches.
У каждого объекта Touch есть определенные свойства, которые мы кратко описали в таблице 8.26.
атрибут Touch | Описание |
---|---|
clientX, clientY | Сенсорные координаты относительно окна |
screenX, screenY | Сенсорные координаты относительно экрана |
pageX, pageY | Сенсорные координаты относительно всей страницы, в том числе положение прокрутки |
identifier | Номер для идентификации касания между событиями |
target | Оригинальный HTML элемент, где возникает событие |
Следующий пример кода при касании показывает под пальцем на экране синий круг размером в 20px:
<!DOCTYPE html PUBLIC "-//WAPFORUM//DTD XHTML Mobile 1.0//EN" "http://www.wapforum.org/DTD/xhtml-mobile10.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> <title>iPhone Multitouch</title> <meta name="viewport" content="width=device-width; initial-scale=1.0; maximum-scale=1.0; user-scalable=0;"> <style type="text/css"> .point { width: 20px; height: 20px; position: absolute; -webkit-border-radius: 10px; background-color: blue; } </style> <script type="text/javascript"> function touch(event) { event.preventDefault(); for (var i=0; i<event.touches.length; i++) { var top = event.touches[i].pageY-10; var left = event.touches[i].pageX-10; var html = "<div class='point' style='left: " + left + "px ; top: " + top + "px'></div>"; document.getElementById("container").innerHTML += html; } } function clean() { document.getElementById("container").innerHTML = ""; } </script> </head> <body> <div ontouchstart="touch(event)" ontouchend="clean()" id="container" style="background-color:red; width: 300px; height: 300px"> </div> </body> </html>
События фокуса и события формы
В таблице 8.27 информация про уровень поддержки в разных мобильных браузерах событий <onfocus>, <onblur>, <onchange>, и <onsubmit> (только для форм).
Браузер/ Платформа | onfocus | onblur | onchange | onsubmit |
---|---|---|---|---|
Safari | Да | Да | Да | Да |
браузер Android | Да | Да | Да | Да |
Symbian/S60 | Да | Да | Да | Да |
Nokia Series 40 | Да | Нет | Нет | Да |
webOS | Да | Да | Да | Да |
BlackBerry | Да | Да | Да | Да |
NetFront | Да | Да | Да | Да |
Internet Explorer | Да | Нет | Да | Да |
Motorola Internet Browser | Нет | Нет | Нет | Нет |
Opera Mobile | Да | Да | Да | Да |
Opera Mini | Нет | Да | Нет | Да |
События Over
События over включают mouseover и mouseout и эти события обычно используются для создания эффекта при наведения курсора на определенный элемент. В качестве «must-have» эти события точно не рекомендуется использовать в мобильных веб-сайтах, так как работать они будут только в браузерах с курсор-навигацией. В тач- и фокус-браузерах просто нет состояния «over», оно заменяется состоянием active или focus для браузеров с фокусной навигацией.
В Safari на iOS для тех ситуаций, когда пользователь прокручивает элемент, используя одновременно два пальца, поддерживается событие <onchange>, и <onmousewheel>.
События изменения размера, прокрутки и изменения положения.
Когда пользователь активирует прокрутку по документу, некоторые браузеры применяют событие <onscroll> ко всему документу целиком. Другие поддерживают событие <onresize>, которое включается, когда изменяется размер окна. В отличие от декстопного браузера, в мобильном пользователь не может точно так же изменить размеры окна, но размер окна может измениться при изменении положения самого устройства: от портретного к альбомному и наоборот.
В мобильном дизайне стоит использовать процентные значения для ширины. Такие значения автоматически работают на всех устройствах и позволяют твоему приложению подстраиваться под любое положение устройства. К сожалению, в некоторых устройствах (как в Nokia N70) в работе процентных значений есть некоторые ошибки и получаются ситуации, когда блок «обтекает» контент и появляется ужасная полоса горизонтальной прокрутки.
Начиная с iOS 2.0 в Safari предлагаются событие окна onorientationchang и свойство orientation. У этого свойства в портретном режиме значение 0, в альбомном режиме 90, а в обратном альбомном режиме -90. Мы можем его использовать для изменений в DOM или использовать шаблон body class (рассмотрим его в Главе 12) чтобы изменить весь макет:
if (window.onorientationchange) { window.onorientationchange = function() { var orientation = window.orientation; switch(orientation) { case 0: // Portrait break; case 90: // Landscape to the left break; case −90: // Landscape to the right break; } } }
В Nokia N97 виджеты на главном экране — просто веб-документы, которые при переходе от режима full screen в режим home screen (и наоборот) запускают событие onresize.
На не- iPhone устройствах, которые поддерживают onresize, мы можем обнаружить изменение положения при помощи следующего кода:
if (window.onresize) { if (screen.width>screen.height) { // Landscape } else { // Portrait } }
В Таблице 8.28 указано, какие браузеры поддерживают события onscroll и onresize.
Браузер/ Платформа | onscroll | onresize |
---|---|---|
Safari | Да | Да |
браузер Android | Да | Да |
Symbian/S60 | Да | Да, и даже тогда, когда панель скрыта |
Nokia Series 40 | Нет | Нет |
webOS | Да | Да |
BlackBerry | Нет | На некоторых устройствах |
NetFront | Нет | Нет |
Internet Explorer | Нет | Нет |
Motorola Internet Browser | Нет | Нет |
Opera Mobile | Нет | Да |
Opera Mini | Нет | Нет |
События клавиш
События кнопок — <onkeypress>, <onkeyup> и <onkeydown> — позволяют нам обнаружить нажатие клавиш по странице в целом (<body>) или на одном элементе (как правило, это текстовое поле). На устройствах, где есть необходимая поддержка, это может быть полезно во многих ситуациях:
- для обеспечения возможности использования сочетаний клавиш;
- для навигации или движений в играх или приложениях;
- для отправки данных формыпо нажатию кнопки Enter (или любой другой кнопки);
- для запрета ввода каких-нибудь символов в текстовом поле.
Если хочешь запретить использование клавиш — подумай хорошо о всех плюсах и минусах такого решени. Помни, что в разных устройствах клавиатуры могут кардинально отличаться. В некоторых мобильных есть только экранные клавиатуры, в других — цифровые, а в третьих — QWERTY. Из-за такого разнообразия на некоторых платформах с могут возникнуть некоторые сложности.
Из таблицы 8.29 можешь узнать, в каких браузерах поддерживаются события клавиш для <body> и текстовых полей ввода.
Браузер/ Платформа | Поддержка onkeypress, onkeyup, и onkeydown | Поддержка onkeypress в текстовых полях ввода |
---|---|---|
Safari | Нет | Да |
браузер Android | Да, но это также открывает адресную строку | Да |
Symbian/S60 | Да | Да |
Nokia Series 40 | Да | Нет |
webOS | Да, но это также открывает адресную строку | Да |
BlackBerry | Да | Нет |
NetFront | Нет | Нет |
Internet Explorer | Да | Нет |
Motorola Internet Browser | Нет | Нет |
Opera Mobile | Нет | Да |
Opera Mini | Нет | Нет |
Если в устройстве есть QWERTY клавиатура, то при помощи свойств события можно обнаружить (при их наличии) некоторые клавиши-модификаторы вроде Ctrl, Alt или Shift.
При помощи следующего кода можно сделать простой тест для получения кодов клавиш:
<script type="text/javascript"> window.onkeyup = function(event) { // charCode depends on modifiers (as shift), keyCode not var code = event.keyCode ? event.keyCode : event.charCode; alert( "code: " + code + " - ASCII value: " + String.fromCharCode(code)); }; </script>
Полезные клавиши для некоторых устройств
В Safari на iOS при открытой экранной клавиатуре и фокусе текстового поля, мы можем при помощи keyCode получить информацию о каждой нажатой клавише. В таблице 8.30 приведены некоторые наиболее важные коды.
Клавиша | keyCode |
---|---|
Backspace/Del | 127 |
Enter | 10 |
Space | 32 |
Android и webOS (Palm) устройства бывают как с физической клавиатурой, так и без нее. В Таблице 8.31 приведены возможные специальные значения key для этих устройств.
Клавиша | keyCode |
---|---|
Backspace/Del | 8 |
Enter | 13 |
Space | 32 |
В Nokia N97 есть полноценная QWERTY-клавиатура, но если пользователь не нажимает одновременно клавишу Shift, то клавиши с буквами не предоставляют правильные значения ASCII. Например, кнопки H и I дадут одинаковый keyCode (56), а charCodes — разные. По умолчанию, для charCodes значения Unicode — цифровые или символьные значения клавиши (обычно используется с клавишей Sym). Если пользователь использует экранную клавиатуру (экранная клавиатура доступна только в виде всплывающего окна, когда фокус находится на соответствующем поле) — передается каждый введенный символ (независимо от того, был он введен на цифровой клавиатуре, сенсорной или при помощи интеллектуального ввода текста). Коды приведены в таблице 8.32.
Key | keyCode | charCode |
---|---|---|
Backspace | 8 | 8 |
Enter | 13 | 13 |
Space | 32 | 32 |
Up | 38 | 63497 |
Down | 40 | 63498 |
Left | 37 | 63495 |
Right | 39 | 63496 |
Fire | N/A | 63557 |
Даже если мы перехватим нажатие клавиш, помни что специальные клавиши (Menu, Call, End, Volume) находятся вне компетенции веб-разработчика и мы не можем их отследить.
В устройствах на Symbian 3-го поколения (Nokia N95, E61 и др.) нет сенсора — там цифровая клавиатура. В таблице 8.33 показано какие события клавиш мы можем перехватить в таких устройствах.
Клавиша | keyCode | charCode |
---|---|---|
Clear | 8 | 8 |
Send | N/A | 63586 |
Cursor и Fire | N/A | N/A |
Предотвращение поведения по умолчанию
Практически для каждого события мы можем предотвратить поведение по умолчанию при помощи метода event.preventDefault или используя перехват события и возвращении false. Применяется это обычно с событием <onsubmit> для отмены передачи на сервер невалидных данных. Или например, для запрета перехода по ссылке:
<a href="news/" onclick="news();return false">Go to news</a>
Приведенный выше код — стандартна ссылка news.html, но если в устройстве есть поддержка JavaScript, то мы можем перехватить событие onclick, вызвать локальную функцию (которая может получить news при помощи Ajax) и при помощи передачи false отменить нормальное поведение ссылки. Такие действия позволяют избежать загрузки страницы и уменьшают сетевой трафик.
При помощи отмены события <onkeyup> мы можем предотвратить использование клавиши. Использовать этот способ нужно очень и очень осторожно и только на совместимых и проверенных устройствах.
В таблице 8.34 можешь посмотреть, какие браузеры поддерживают эти три сценария.
Браузер/ Платформа | onsubmit | onclick на ссылках | onkeyup |
---|---|---|---|
Safari | Да | Да | Частично |
браузер Android | Да | Да | Нет |
Symbian/S60 | Да | Да | Частично |
Nokia Series 40 | Да | Да | Нет |
webOS | Да | Да | Частично |
BlackBerry | Да | Да | Нет |
NetFront | Да | Да | Да |
Internet Explorer | Да | Да | Нет |
Motorola Internet Browser | Да | Да | Нет |
Opera Mobile | Да | Да | Нет |
Opera Mini | Да | Да | Нет |
Куда дальше
- следующая — Сенсорные жесты
- предыдущая — Изменение стилей
- содержание