Обработка событий

Автор: Анна Лысак и Татьяна Головко Дата публикации: 13.07.2011

Одной из наиболее часто используемых функций Javascript является обработка событий. Давай посмотрим, как мобильные браузеры справляются с этой задачей.

Управление событиями

Мы можем указать в скриптах обработку событий при помощи следующих методов (в таблице 8.22 можешь посмотреть, какие браузеры поддерживают эти методы):

  • использование HTML атрибутов (вроде onclick="alert('sample')");
  • использование JavaScript свойства объекта (element.onclick = function(){});
  • использование DOM-метода addEventListener.

В Internet Explorer вместо метода DOM addEventListener, Microsoft использует свойство элемента attachEvent.

Табл. 8.22. Таблица поддержки регистрации событий
Браузер/ Платформа атрибут 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 приведены данные о поддержке всех этих событий в разных браузерах.

Табл. 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 приведена информация, как разные браузеры поддерживают эти события.

Табл. 8.24. Таблица поддержки событий click
Браузер/ Платформа 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.

Табл. 8.25. TouchEvent набор
атрибут TouchEvent Описание
touches Все прикосновения на самом деле на экране
targetTouches Только прикосновения внутри целевого элемента события
changedTouches Только прикосновения, которые изменились с момента последнего вызова события (полезно в ontouchmove и ontouchend или для фильтрации только новых или удаленных касаний)

Если пользователь уберет с экрана палец, то это действие будет доступно только в наборе changedTouches. В Android удаленное касание также доступно в наборе touches.

У каждого объекта Touch есть определенные свойства, которые мы кратко описали в таблице 8.26.

Табл. 8.26. Свойства объекта Touch
атрибут 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> (только для форм).

Табл. 8.27. Таблица совместимости форматов изображений
Браузер/ Платформа 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.

Табл. 8.28. Таблица поддержки событий scroll и resize
Браузер/ Платформа 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> и текстовых полей ввода.

Табл. 8.29. Таблица поддержки событий клавиш
Браузер/ Платформа Поддержка 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 приведены некоторые наиболее важные коды.

Табл. 8.30. Использование keyCodes в Safari
Клавиша keyCode
Backspace/Del 127
Enter 10
Space 32

Android и webOS (Palm) устройства бывают как с физической клавиатурой, так и без нее. В Таблице 8.31 приведены возможные специальные значения key для этих устройств.

Табл. 8.31. Использования keyCodes в Android и webOS
Клавиша keyCode
Backspace/Del 8
Enter 13
Space 32

В Nokia N97 есть полноценная QWERTY-клавиатура, но если пользователь не нажимает одновременно клавишу Shift, то клавиши с буквами не предоставляют правильные значения ASCII. Например, кнопки H и I дадут одинаковый keyCode (56), а charCodes — разные. По умолчанию, для charCodes значения Unicode — цифровые или символьные значения клавиши (обычно используется с клавишей Sym). Если пользователь использует экранную клавиатуру (экранная клавиатура доступна только в виде всплывающего окна, когда фокус находится на соответствующем поле) — передается каждый введенный символ (независимо от того, был он введен на цифровой клавиатуре, сенсорной или при помощи интеллектуального ввода текста). Коды приведены в таблице 8.32.

Табл. 8.32. Использование keyCodes в Symbian 5-м выпуске
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 показано какие события клавиш мы можем перехватить в таких устройствах.

Табл. 8.33. Использование keyCodes в Symbian 3-й выпуск
Клавиша keyCode charCode
Clear 8 8
Send N/A 63586
Cursor и Fire N/A N/A

Предотвращение поведения по умолчанию

Практически для каждого события мы можем предотвратить поведение по умолчанию при помощи метода event.preventDefault или используя перехват события и возвращении false. Применяется это обычно с событием <onsubmit> для отмены передачи на сервер невалидных данных. Или например, для запрета перехода по ссылке:

	<a href="news.html" onclick="news();return false">Go to news</a>

Приведенный выше код — стандартна ссылка news.html, но если в устройстве есть поддержка JavaScript, то мы можем перехватить событие onclick, вызвать локальную функцию (которая может получить news при помощи Ajax) и при помощи передачи false отменить нормальное поведение ссылки. Такие действия позволяют избежать загрузки страницы и уменьшают сетевой трафик.

При помощи отмены события <onkeyup> мы можем предотвратить использование клавиши. Использовать этот способ нужно очень и очень осторожно и только на совместимых и проверенных устройствах.

В таблице 8.34 можешь посмотреть, какие браузеры поддерживают эти три сценария.

Табл. 8.34. Таблица поддержки предотвращений событий по умолчанию
Браузер/ Платформа onsubmit onclick на ссылках onkeyup
Safari Да Да Частично
браузер Android Да Да Нет
Symbian/S60 Да Да Частично
Nokia Series 40 Да Да Нет
webOS Да Да Частично
BlackBerry Да Да Нет
NetFront Да Да Да
Internet Explorer Да Да Нет
Motorola Internet Browser Да Да Нет
Opera Mobile Да Да Нет
Opera Mini Да Да Нет

Куда дальше