Свойства объекта событие

В объекте события содержится подробнейшая информация о том, что и где произошло.

К сожалению, здесь много кросс-браузерных несовместимостей, однако самые важные из них легко преодолимы.

Тип события

Тип события можно получить, используя кроссбраузерное свойство type объекта событие.

function getEventType(e) {
	if (!e) e = window.event;
	alert(e.type);
}

Данный код в действии (в примере обрабатываются события click и mouseout):

Элементы, связанные с событием

Элемент-триггер: target

Чаще всего нужно узнать, на каком элементе сработало событие.

Например, мы поймали на внешнем div'е и хотим знать, на каком из внутренних элементов оно на самом деле произошло.

В Internet Explorer у объекта window.event для этого есть свойство srcElement, в остальных браузерах, работающих по рекомендациям W3C, для этого используется event.target.

Вот пример использования этого свойства. Обработчик стоит только на внешнем диве, но благодаря event.target выводит по клику класс исходного элемента.

<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-обработчик в примере висит только на внешнем диве d1 и выглядит примерно так:

function(event) {
  // получить объект событие.
  // вместо event лучше писать window.event
  event = event || window.event

  // кросс-браузерно получить target
  var t = event.target || event.srcElement

  alert(t.className)
}

Когда триггеров больше одного: relatedTarget

Для событий mouseout и mouseover предусмотрен способ получить как элемент на который курсор мыши перешел, так и элемент, с которого он перешел.

Эти свойства - relatedTarget в W3C, и fromElement/toElement в 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 - элемент, *!*на который*/!* перешел курсор мыши
}

Свойство relatedTarget дополняет target. В нем всегда находится информация о втором элементе, участвовавшем в событии.

Поэтому его можно получить для IE, взяв то свойство из fromElement/srcElement, которое не равно target:

if (!e.relatedTarget && e.fromElement) {
  e.relatedTarget = (e.fromElement==e.target) ? e.toElement : e.fromElement
}

Текущий элемент: this

При всплытии - событие по очереди вызвает обработчики на элементе-триггере и дальше, вверх по документу.

По мере всплытия, текущим элементом каждый раз становится новый. Иначе говоря. текущий элемент - это тот, к которому в данный момент "доплыло" событие.

Стандартный способ получить текущий элемент - использовать переменную this.

Например, при клике на внутренний div, код в этом примере последовательно отмечает элементы, на которых регистрируется всплывающее событие:

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>

Кнопка мыши: which/button.

После получения события обычно интересно узнать, какая кнопка была нажата. Если, конечно, это не событие contextmenu, с которым все и так понятно

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

  Internet Explorer Firefox, Safari Win и Opera Konqueror
ЛЕВАЯ КНОПКА event.which undefined 1 1
event.button 1 0 1
СРЕДНЯЯ КНОПКА event.which undefined 2 2
event.button 4 1 4
ПРАВАЯ КНОПКА event.which undefined 3 3
event.button 2 2 2

Свойство event.which было изначально изобретено Netscape, а event.button использовалось в Internet Explorer.
Через некоторое время браузеры стали использовать оба и все перепуталось.

Сравнение подходов

Стандарт/Firefox

В стандарте W3C прописано свойство button, которое ведет себя, как в Firefox, т.е:

  • 0 - левая кнопка
  • 1 - средняя кнопка
  • 2 - правая кнопка

IE

Подход создателей браузера Internet Explorer, вообще говоря, более универсальный, так как button является 3-битовым числом, каждый бит которого отвечает за кнопку мыши.

Так, button & 1 (первый бит) установлен в 1, если нажата левая кнопка, button & 2 (второй бит) установлен в 1, если нажата правая кнопка, и button & 4 (третий бит) - если нажата средняя.

В результате мы не можем отловить, когда, например, нажаты левая и правая кнопки, а когда только левая или только правая. К сожалению, это можно сделать только в IE.

Кросс-браузерный код

Удобнее всего - взять за основу свойство which, которое одинаково поддерживают почти все браузеры.

Остается лишь составить which из button для Internet Explorer:

if (!e.which && e.button) {
  if (e.button & 1) e.which = 1
  else if (e.button & 4) e.which = 2
  else if (e.button & 2) e.which = 3
}

Тест-стенд

Вот универсальный тестовый стенд по определению клавиш. Выбирайте любую мышь и жмите кнопу из любого браузера - ниже появятся названия событий и значения which/button.


Координаты мыши: clientX(Y)/pageX(Y)

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

Относительно окна

Координаты курсора мыши относительно окна находятся в стандартных свойствах clientX/clientY. Они одинаково поддерживается всеми браузерами.

Если у вас есть окно 500x500, и мышь находится в центре, то clientX и clientY будут оба равны 250. Если вы затем проскроллируете документ вниз, налево или вверх, не двигая курсор - значения clientX/clientY не изменятся, так как отсчитываются относительно окна, а не документа.

Относительно документа

Как правило, при обработке события нужна позиция мыши относительно документа, учитывающая прокрутку. Стандарт W3C предоставляет для этого свойство pageX/pageY.

Если у вас есть окно 500x500, и мышь находится в центре, то pageX и pageY будут оба равны 250. Если вы затем проскроллируете на 250 пикселей вниз, pageY станет равным 750.

Таким образом pageX/pageY содержат координаты, на каком месте документа произошло событие, учитывая все прокрутки.

Свойства pageX/pageY поддерживаются всеми браузерами, кроме Internet Explorer.

В IE их можно получить из clientX/clientY, прибавив к ним scrollLeft/scrollTop.

Обычно оно находится в <body>: document.body.scrollLeft, но это не всегда так. Например, при выборе Strict DTD оно высчитывается для <html>: document.documentElement.scrollLeft. Кроме того, тэга <body> может просто не быть в документе.

Поэтому мы сначала возьмем html.scrollLeft (если есть), затем проверим body.scrollLeft. Если нет ни того, ни того, то 0.

var html = document.documentElement
var body = document.body
e.pageX = e.clientX + (html && html.scrollLeft || body && body.scrollLeft || 0)

Кроме того, document в IE может быть немного сдвинут с позиции 0,0. Значение сдвига находится в document.documentElement.clientLeft/clientTop, и его также необходимо учесть.

Этот код позволяет надежно получить pageX/pageY для 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)
}

Демо

Этот обработчик mouseMove обновляет координаты мыши относительно документа.

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:

Резюме

Вы узнали, как работают и как кросс-браузерно получить основные свойства объекта события:

  • Текущий элемент: this
  • Тип события: event.type
  • Элементы-триггеры: event.target/relatedTarget
  • Кнопка мыши: event.which
  • Курсор относительно окна: event.clientX/clientY
  • Курсор относительно документа: event.pageX/pageY

Кроме того, увидели их в действии на демо.

Этих свойств хватает для 95% задач, связанных с событиями.