Ранее в скриптах
мы с вами часто использовали событие click – щелчок левой
кнопкой мыши. В действительности – это составное событие, то есть, мы сначала
нажимаем левую кнопку, затем отпускаем и только потом генерируется событие click. Причем в
момент нажатия и отпускания кнопки возникают свои события:
mousedown/mouseup
– нажатие и отпускание кнопки мыши.
Давайте в этом
убедимся, возьмем вот такой HTML-документ:
<!DOCTYPE html>
<html>
<head>
<title>Уроки по JavaScript</title>
</head>
<body>
<script>
document.addEventListener("mouseup",
()=>console.log("mouseup"));
document.addEventListener("click",
()=>console.log("click"));
document.addEventListener("mousedown",
()=>console.log("mousedown"));
</script>
</body>
</html>
В нем прописаны
три обработчика на события click, mousedown и mouseup. Теперь кликнем по
документу и в консоли увидим эти три события в порядке:
mousedown
→ mouseup → click
И это
стандартизированный порядок: данные события возникают именно в такой
последовательности. Для двойного
клика тоже есть свое событие dblclick. Добавим его:
document.addEventListener("dblclick",
()=>console.log("dblclick"));
Теперь при
двойном щелчке левой кнопкой мыши, мы видим такие события:
mousedown
→ mouseup → click → mousedown → mouseup → click
→ dblclick
Эта
последовательность также стандартизирована и события следуют друг за другом
именно в таком порядке.
Для событий mousedown
и mouseup в объекте event полезным является еще одно свойство:
-
event.which
== 1 – левая кнопка;
-
event.which
== 2 – средняя кнопка;
-
event.which
== 3 – правая кнопка.
Отобразим его:
document.addEventListener("mousedown",
(event)=>console.log("mousedown: "+event.which));
document.addEventListener("mouseup",
(event)=>console.log("mouseup: "+event.which));
Теперь мы знаем
какая кнопка мыши была нажата при возникновении данных событий.
Также часто
совместно с мышью используется клавиатура. Например, в графических редакторах
клавиши Alt (или Opt для Mac), Ctrl, Shift и Cmd для Mac добавляют
функционал манипулятору «мышь». Чтобы в событиях мыши проверить: была ли
дополнительно нажата еще какая-либо функциональная клавиша, используются
следующие свойства объекта event:
-
event.shiftKey – true, если нажата
клавиша Shift и false в противном
случае;
-
event.altKey – true при нажатом Alt (или Opt для Mac) и false иначе;
-
event.ctrlKey – true при нажатом Ctrl
и false иначе;
-
event.metaKey – true при нажатом Cmd
(для Mac) и false иначе.
Обрабатывать их
достаточно просто, например так:
document.addEventListener("click",
(event) => {
if(event.shiftKey && event.ctrlKey)
console.log("click");
});
Мы здесь увидим
сообщение «click» только если
при клике были нажаты клавиши Shift и Ctrl.
Обратите
внимание, когда мы пишем браузерные скрипты, то предполагаем, что они могут
быть запущены на самых разных компьютерах с разными ОС, в том числе и Mac OS. Так вот, в ОС Mac пользователи
вместо клавиши Ctrl нажимают на клавишу Cmd. И это следует
учесть в скрипте, например, так:
if(event.shiftKey && (event.ctrlKey || event.metaKey))
console.log("click");
Здесь мы
проверяем не только Ctrl, но и свойство metaKey, отвечающее за нажатие на
кнопку Cmd.
Также не нужно
забывать и про пользователей мобильных устройств с отсутствующей клавиатурой.
Так что они вряд ли смогут перемещать курсор мыши с нажатой клавишей Shift!
Кроме клавиш,
объект event для событий от
мыши, содержит свойства:
-
clientX/clientY
– координаты курсора мыши относительно окна браузера;
-
pageX/pageY
– координаты курсора мыши относительно HTML-документа.
Например, для
события mousemove будем выводить координаты курсора мыши в консоль:
document.addEventListener("mousemove",
(event)=>console.log("mousemove: "+event.clientX+", "+event.clientY));
Аналогично
работают свойства pageX/pageY.
Следующие два
события мыши
-
mouseover
– возникает при наведении курсора мыши на элемент HTML-документа;
-
mouseout – возникает при
покидании курсора мыши элемента HTML-документа.
Например,
у нас есть вот такое содержимое страницы:
<div class="parent">DIV
<p class="child">P</p>
</div>
Со стилями:
<style>
.parent {background: #CC4444; padding: 10px 0 10px 10px;
display: inline-block;width: 100px;}
.child {background: #00CC00; padding: 10px;}
</style>
И
добавим обработчик события mouseover:
document.addEventListener("mouseover", (event)=>{
let prop = "target = "+event.target.tagName;
if(event.relatedTarget != null)
prop+=", relatedTarget = "+event.relatedTarget.tagName;
console.log("mouseover: "+prop);
});
Здесь
у объекта event мы используем
два новых свойства:
-
target – ссылка на
объект над которым находится курсор мыши;
-
relatedTarget
– ссылка на объект, с которого ушел курсор мыши.
Давайте
посмотрим, как это все будет работать. Объясняем.
А
вот для другого события mouseout эти свойства работают с точностью
наоборот:
-
relatedTarget
– ссылка на объект над которым находится курсор мыши;
-
target – ссылка на
объект, с которого ушел курсор мыши.
Изменим в
обработчике событие на mouseout и обновим документ. Видите, эти
свойства работают именно так, что логично, так как событие mouseout возникает при
покидании элемента, значит target будет тем элементом, с которого
мы ушли, а relatedTarget – элементом где мы сейчас находимся.
События mouseover
и mouseout всплывают от
целевого элемента, где они произошли и доходят до корня DOM-дерева –
объекта document. Например, если
повесить событие mouseover на тег div:
let div = document.querySelector("div.parent");
div.addEventListener("mouseover", showInfo);
function showInfo(event) {
let prop = "target = "+event.target.tagName;
if(event.relatedTarget != null)
prop+=", relatedTarget = "+event.relatedTarget.tagName;
let name = event.currentTarget.tagName;
console.log(name+" mouseover: "+prop);
}
То при наведении
курсора на дочерний элемент p, увидим событие mouseover. Причем при
переходе с дочернего элемента и обратно также генерируется это событие.
Если же мы хотим
чтобы событие возникало один раз при наведении на него курсора мыши, то можно воспользоваться
эквивалентными событиями:
mouseenter
и
mouseleave
которые похожи на
mouseover/mouseout, но:
- Не всплывают.
- Событие mouseenter
генерируется когда указатель оказывается над элементом и при этом не важно:
потомок это элемента или сам элемент.
- Событие mouseleave
срабатывает при покидании элемента целиком (дочерние элементы здесь не
учитываются).
Например,
заменим событие mouseover на mouseenter, получим. Смотрите, теперь при переходе
между дочерним элементом и div дополнительных событий не возникает.
Аналогично работает и mouseleave.
Из-за того, что
события mouseenter и mouseleave не всплывают, они не могут быть делегированы
обработчику верхнего уровня, например, для объекта document:
document.addEventListener("mouseenter", showInfo);
так работать не будет. Но, если прописать
событие
document.addEventListener("mouseover", showInfo);
то мы его
успешно перехватываем. Вот эти ограничения следует учитывать при использовании
событий mouseenter и mouseleave.
Итак, на этом
занятии мы с вами рассмотрели работу следующих событий мыши:
mousedown/mouseup
|
При нажатии и
отпускании кнопки мыши
|
click
|
При щелчке
левой кнопкой мыши
|
dblclick
|
При двойном
щелчке левой кнопкой мыши
|
mousemove
|
При
перемещении мыши
|
mouseover/mouseout
|
При наведении
и покидании курсора мыши на элемент
|
mouseenter/mouseleave
|
При наведении
и покидании курсора мыши на элемент (не всплывают и не учитывают дочерние
элементы)
|
Также мы с вами
рассмотрели следующие свойства объекта event:
event.which
|
Номер нажатой
кнопки мыши
|
event.shiftKey/altKey/ctrlKey/metaKey
|
Флаги,
указывающие на соответствующую нажатую кнопку клавиатуры
|
event.clientX/clientY
|
Координаты
курсора мыши относительно окна браузера
|
event.pageX/pageY
|
Координаты
курсора мыши относительно HTML-документа
|
event.target/ relatedTarget
|
Ссылки на
объекты в зависимости от типов события: mouseover/mouseout
|