События мыши

Ранее в скриптах мы с вами часто использовали событие 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, но:

  1. Не всплывают.
  2. Событие mouseenter генерируется когда указатель оказывается над элементом и при этом не важно: потомок это элемента или сам элемент.
  3. Событие 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

Видео по теме