В этой главе мы более детально рассмотрим события мыши и их свойства.
Сразу заметим: эти события бывают не только из-за мыши, но и эмулируются на других устройствах, в частности, на мобильных, для совместимости.
Типы событий мыши
Мы можем разделить события мыши на две категории: «простые» и «комплексные».
Простые события
Самые часто используемые простые события:
mousedown/mouseup
- Кнопка мыши нажата/отпущена над элементом.
mouseover/mouseout
- Курсор мыши появляется над элементом и уходит с него.
mousemove
- Каждое движение мыши над элементом генерирует это событие.
contextmenu
- Вызывается при попытке открытия контекстного меню, как правило, нажатием правой кнопки мыши. Но, заметим, это не совсем событие мыши, оно может вызываться и специальной клавишей клавиатуры.
…Есть также несколько иных типов событий, которые мы рассмотрим позже.
Комплексные события
click
- Вызывается при
mousedown
, а затемmouseup
над одним и тем же элементом, если использовалась левая кнопка мыши. dblclick
- Вызывается двойным кликом на элементе.
Комплексные события состоят из простых, поэтому в теории мы могли бы без них обойтись. Но хорошо, что они существуют, потому что работать с ними очень удобно.
Порядок событий
Одно действие может вызвать несколько событий.
Например, клик мышью вначале вызывает mousedown
, когда кнопка нажата, затем mouseup
и click
, когда она отпущена.
В случае, когда одно действие инициирует несколько событий, порядок их выполнения фиксирован. То есть обработчики событий вызываются в следующем порядке: mousedown
→ mouseup
→ click
.
Кликните на кнопку ниже, и вы увидите события. Также попробуйте двойной клик.
В окне теста ниже все события мыши записываются, и если задержка между ними более 1 секунды, то они разделяются горизонтальной чертой.
При этом мы также можем увидеть свойство which
, которое позволяет определить, какая кнопка мыши была нажата.
Получение информации о кнопке: which
События, связанные с кликом, всегда имеют свойство which
, которое позволяет определить нажатую кнопку мыши.
Это свойство не используется для событий click
и contextmenu
, поскольку первое происходит только при нажатии левой кнопкой мыши, а второе – правой.
Но если мы отслеживаем mousedown
и mouseup
, то оно нам нужно, потому что эти события срабатывают на любой кнопке, и which
позволяет различать между собой «нажатие правой кнопки» и «нажатие левой кнопки».
Есть три возможных значения:
event.which == 1
– левая кнопкаevent.which == 2
– средняя кнопкаevent.which == 3
– правая кнопка
Средняя кнопка сейчас – скорее экзотика, и используется очень редко.
Модификаторы: shift, alt, ctrl и meta
Все события мыши включают в себя информацию о нажатых клавишах-модификаторах.
Свойства объекта события:
shiftKey
: ShiftaltKey
: Alt (или Opt для Mac)ctrlKey
: CtrlmetaKey
: Cmd для Mac
Они равны true
, если во время события была нажата соответствующая клавиша.
Например, кнопка внизу работает только при комбинации Alt+Shift+клик:
<button id="button">Нажми Alt+Shift+Click на мне!</button>
<script>
button.onclick = function(event) {
if (event.altKey && event.shiftKey) {
alert('Ура!');
}
};
</script>
Cmd
вместо Ctrl
В Windows и Linux клавишами-модификаторами являются Alt, Shift и Ctrl. На Mac есть ещё одна: Cmd, которой соответствует свойство metaKey
.
В большинстве приложений, когда в Windows/Linux используется Ctrl, на Mac используется Cmd.
То есть, когда пользователь Windows нажимает Ctrl+Enter и Ctrl+A, пользователь Mac нажимает Cmd+Enter или Cmd+A, и так далее.
Поэтому, если мы хотим поддерживать такие комбинации, как Ctrl+клик, то для Mac имеет смысл использовать Cmd+клик. Это удобней для пользователей Mac.
Даже если мы и хотели бы заставить людей на Mac использовать именно Ctrl+клик, это довольно сложно. Проблема в том, что левый клик в сочетании с Ctrl интерпретируется как правый клик на MacOS и генерирует событие contextmenu
, а не click
как на Windows/Linux.
Поэтому, если мы хотим, чтобы пользователям всех операционных систем было удобно, то вместе с ctrlKey
нам нужно проверять metaKey
.
Для JS-кода это означает, что мы должны проверить if (event.ctrlKey || event.metaKey)
.
Комбинации клавиш на клавиатуре – это хорошее дополнение к рабочему процессу. Если у пользователя есть клавиатура – они работают. Ну а если на его устройстве её нет – должен быть другой способ сделать то же самое.
Координаты: clientX/Y, pageX/Y
Все события мыши имеют координаты двух видов:
- Относительно окна:
clientX
иclientY
. - Относительно документа:
pageX
иpageY
.
Например, если у нас есть окно размером 500x500, и курсор мыши находится в левом верхнем углу, то значения clientX
и clientY
равны 0
. А если мышь находится в центре окна, то значения clientX
и clientY
равны 250
независимо от того, в каком месте документа она находится и до какого места документ прокручен. В этом они похожи на position:fixed
.
Наведите курсор мыши на поле ввода, чтобы увидеть clientX/clientY
(пример находится в iframe
, поэтому координаты определяются относительно этого iframe
):
<input onmousemove="this.value=event.clientX+':'+event.clientY" value="Наведи на меня мышь">
Координаты относительно документа pageX
, pageY
отсчитываются не от окна, а от левого верхнего угла документа. Подробнее о координатах вы можете узнать в главе Координаты.
Отключаем выделение
Двойной клик мыши имеют побочный эффект, который может быть неудобен в некоторых интерфейсах: он выделяет текст.
Например, двойной клик на текст ниже выделяет его в дополнение к нашему обработчику:
<span ondblclick="alert('dblclick')">Сделайте двойной клик на мне</span>
Если зажать левую кнопку мыши и, не отпуская кнопку, провести мышью, то также будет выделение, которое в интерфейсах может быть «не кстати».
Есть несколько способов запретить выделение, о которых вы можете прочитать в главе Selection и Range.
В данном случае самым разумным будет отменить действие браузера по умолчанию при событии mousedown
, это отменит оба этих выделения:
До...
<b ondblclick="alert('Клик!')" onmousedown="return false">
Сделайте двойной клик на мне
</b>
...После
Теперь выделенный жирным элемент не выделяется при двойном клике, а также на нём нельзя начать выделение, зажав кнопку мыши.
Заметим, что текст внутри него по-прежнему можно выделить, если начать выделение не на самом тексте, а до него или после. Обычно это нормально воспринимается пользователями.
Если мы хотим отключить выделение для защиты содержимого страницы от копирования, то мы можем использовать другое событие: oncopy
.
<div oncopy="alert('Копирование запрещено!');return false">
Уважаемый пользователь,
Копирование информации запрещено для вас.
Если вы знаете JS или HTML, вы можете найти всю нужную вам информацию в исходном коде страницы.
</div>
Если вы попытаетесь скопировать текст в <div>
, у вас это не получится, потому что срабатывание события oncopy
по умолчанию запрещено.
Конечно, пользователь имеет доступ к HTML-коду страницы и может взять текст оттуда, но не все знают, как это сделать.
Итого
События мыши имеют следующие свойства:
-
Кнопка:
which
. -
Клавиши-модификаторы (
true
если нажаты):altKey
,ctrlKey
,shiftKey
иmetaKey
(Mac).- Если вы планируете обработать Ctrl, то не забудьте, что пользователи Mac обычно используют Cmd, поэтому лучше проверить
if (e.metaKey || e.ctrlKey)
.
- Если вы планируете обработать Ctrl, то не забудьте, что пользователи Mac обычно используют Cmd, поэтому лучше проверить
-
Координаты относительно окна:
clientX/clientY
. -
Координаты относительно документа:
pageX/pageY
.
Действие по умолчанию события mousedown
– начало выделения, если в интерфейсе оно скорее мешает, его можно отменить.
В следующей главе мы поговорим о событиях, которые возникают при передвижении мыши, и об отслеживании смены элементов под указателем.
Комментарии
<code>
, для нескольких строк кода — тег<pre>
, если больше 10 строк — ссылку на песочницу (plnkr, JSBin, codepen…)