W3docs

Основы событий мыши в JavaScript

События мыши в JavaScript: click, dblclick, mousedown, mouseup, mousemove, mouseover, mouseenter, contextmenu. Объект MouseEvent (clientX, pageX, offsetX, button), примеры drag-and-drop и canvas.

Введение

В JavaScript события мыши позволяют странице реагировать на действия пользователя с указателем: клик по кнопке, наведение на ссылку, перетаскивание элемента или вызов контекстного меню правой кнопкой. Привязка скриптов к этим событиям превращает статический документ в интерактивный интерфейс.

В этом руководстве рассматривается полный набор базовых событий мыши, данные, которые можно получить из объекта события (какая кнопка нажата, где находится указатель), важное различие между mouseover и mouseenter, а также несколько запускаемых примеров — переключение цвета, пользовательское контекстное меню, холст для рисования и drag-and-drop. События мыши входят в более широкое семейство событий браузера; если вы только начинаете работать с обработчиками, сначала прочитайте статью Обработка событий в DOM.

Понимание событий мыши в JavaScript

Событие мыши — это сигнал, который браузер генерирует, когда пользователь взаимодействует со страницей с помощью указывающего устройства. Чтобы реагировать на него, нужно зарегистрировать слушатель через addEventListener('eventName', handler). Обработчик получает объект MouseEvent, описывающий произошедшее.

Основные события мыши

СобытиеКогда срабатывает…
clickКнопка нажата и отпущена на одном и том же элементе.
dblclickПо элементу дважды щёлкнули подряд.
mousedownКнопка мыши нажата.
mouseupКнопка мыши отпущена.
mousemoveУказатель перемещается над элементом (срабатывает многократно).
mouseoverУказатель входит в элемент или в один из его дочерних элементов (всплывает).
mouseoutУказатель покидает элемент или один из его дочерних элементов (всплывает).
mouseenterУказатель входит в элемент (не всплывает).
mouseleaveУказатель покидает элемент (не всплывает).
contextmenuНажата правая кнопка мыши, до открытия системного меню.

Полный click на самом деле состоит из трёх событий в следующем порядке: mousedownmouseupclick. Понимание этой последовательности помогает, когда кажется, что одно событие «поглощает» другое.

Чтение объекта MouseEvent

Каждый обработчик мыши получает объект события с полезными свойствами:

  • event.clientX / event.clientY — позиция указателя относительно viewport (видимой области окна).
  • event.pageX / event.pageY — позиция относительно всего документа, включая прокрутку.
  • event.offsetX / event.offsetY — позиция относительно собственного блока целевого элемента.
  • event.button — какая кнопка: 0 = левая, 1 = средняя, 2 = правая.
  • event.ctrlKey / event.shiftKey / event.altKey / event.metaKeytrue, если соответствующая клавиша-модификатор была удержана во время события.
  • event.target — элемент, над которым фактически находился указатель.

Выбор правильных координат имеет значение: используйте clientX/clientY для позиционирования чего-либо фиксированного в окне, pageX/pageY — для позиционирования внутри прокручиваемого содержимого, и offsetX/offsetY (или вычитайте getBoundingClientRect()) — для рисования внутри конкретного элемента, например canvas.

Реализация базовых обработчиков событий мыши

Пример: создание кликабельной кнопки

Рассмотрим кнопку, которая меняет цвет при каждом нажатии. Это простое взаимодействие реализуется с помощью события click.

<div>
    <button id="colorButton">Click me to change color</button>
</div>
<script>
    document.getElementById('colorButton').addEventListener('click', function() {
        this.style.backgroundColor = this.style.backgroundColor === 'red' ? 'blue' : 'red';
    });
</script>

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

Расширенное взаимодействие: событие двойного клика

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

<div>
    <p id="text">Double-click me to toggle text size.</p>
</div>
<script>
    document.getElementById('text').addEventListener('dblclick', function() {
        this.style.fontSize = this.style.fontSize === '16px' ? '32px' : '16px';
    });
</script>

Этот скрипт увеличивает размер шрифта при первом двойном клике и сбрасывает его при следующем, что является практичной функцией для улучшения читаемости.

mouseenter / mouseleave vs. mouseover / mouseout

Это наиболее распространённая ошибка при работе с событиями мыши. mouseover/mouseout всплывают: когда указатель пересекает дочерний элемент, на родителе срабатывает mouseout, а затем снова mouseover — поэтому обработчик на контейнере с дочерними элементами срабатывает многократно. mouseenter/mouseleave не всплывают и срабатывают только один раз, когда указатель пересекает внешнюю границу элемента, игнорируя перемещения между дочерними элементами.

Практическое правило: для простого эффекта наведения на один элемент предпочитайте mouseenter/mouseleave. Используйте mouseover/mouseout только тогда, когда намеренно хотите отслеживать вход в дочерние элементы (например, при делегировании событий).

Пример: подсветка текста при наведении

<div>
  <p id="hoverText">Hover over me to highlight.</p>
</div>
<script>
  document.getElementById('hoverText').addEventListener('mouseenter', function() {
    this.style.color = 'green';
  });
  document.getElementById('hoverText').addEventListener('mouseleave', function() {
    this.style.color = 'black';
  });
</script>

Этот пример улучшает взаимодействие с пользователем, изменяя цвет текста на зелёный при наведении мыши и возвращая его к чёрному при уходе мыши, демонстрируя использование mouseenter и mouseleave.

Использование движения мыши

Пример: отображение координат мыши

В этом примере координаты мыши отображаются в реальном времени по мере того, как пользователь перемещает мышь над текстом. Использование события mousemove отлично подходит для приложений, требующих отслеживания положения мыши. Обратите внимание, что mousemove может срабатывать десятки раз в секунду — держите его обработчик лёгким и избегайте тяжёлых операций с DOM внутри него.

<div>
    <p id="mousePosition" style="height: 100px; background-color: orangered">
 Hover here to track your mouse position!
</p>
</div>
<script>
    document.getElementById('mousePosition').addEventListener('mousemove', function(event) {
        this.textContent = `Mouse Position - X: ${event.clientX}, Y: ${event.clientY}`;
    });
</script>

Этот пример отображает координаты x и y курсора мыши при её движении над текстом, предоставляя пользователю обратную связь в реальном времени.

Продвинутые применения

Реализация пользовательского контекстного меню

Пользовательские контекстные меню — отличный способ улучшить взаимодействие пользователей с опциями правого клика на вашем сайте. Ключевым является event.preventDefault() внутри обработчика contextmenu, который останавливает встроенное меню браузера, давая место вашему собственному.

<div>
<p>Right Click anywhere to see a customized context menu other than the default one in the browser!</p>
</div>
<div>
    <div id="contextMenu" style="display:none; position:absolute; background-color:white; border:1px solid black; padding:10px;">
        <ul>
            <li>Refresh</li>
            <li>Save Page</li>
            <li>Search</li>
        </ul>
    </div>
</div>
<script>
    document.addEventListener('contextmenu', function(event) {
        event.preventDefault();
        let menu = document.getElementById('contextMenu');
        menu.style.display = 'block';
        menu.style.left = `${event.clientX}px`;
        menu.style.top = `${event.clientY}px`;
    });

    document.addEventListener('click', function(event) {
        const menu = document.getElementById('contextMenu');
        if (!menu.contains(event.target)) {
            menu.style.display = 'none';
        }
    });
</script>

Этот JavaScript-код выполняет два основных действия:

  1. При правом клике:
    • Он предотвращает появление стандартного контекстного меню (event.preventDefault()).
    • Он отображает пользовательское меню в месте правого клика, позиционируя его через event.clientX/event.clientY.
  2. При клике в любом месте:
    • Он скрывает пользовательское меню, чтобы оно не оставалось на экране.

Создание интерактивной графики с HTML Canvas

Это интерактивное приложение для рисования позволяет пользователям рисовать на холсте с помощью мыши. Событие mousemove отслеживает движение мыши для рисования линий, что идеально подходит для простых графических приложений или игр.

Пример: простое приложение для рисования

<div>
<p>Start drawing in the box below and see the result!</p>
</div>
<div>
  <canvas id="drawingCanvas" width="400" height="300" style="border:1px solid #000;"></canvas>
</div>
<script>
  const canvas = document.getElementById('drawingCanvas');
  const ctx = canvas.getContext('2d');
  let drawing = false;

  canvas.addEventListener('mousedown', () => {
    drawing = true;
    ctx.beginPath();
  });
  canvas.addEventListener('mouseup', () => drawing = false);
  canvas.addEventListener('mouseout', () => drawing = false);
  canvas.addEventListener('mousemove', function(event) {
    if (drawing) {
      const rect = canvas.getBoundingClientRect();
      ctx.lineTo(event.clientX - rect.left, event.clientY - rect.top);
      ctx.stroke();
    }
  });
</script>

Этот код создаёт область для рисования на веб-странице с помощью элемента <canvas>:

  • JavaScript для рисования:
    • Сначала получается canvas и его контекст рисования, который используется для отрисовки.
    • Рисование начинается, когда вы нажимаете кнопку мыши на холсте, и прекращается, когда вы отпускаете кнопку или выводите указатель за пределы холста.
    • Пока кнопка мыши удерживается и вы перемещаете мышь по холсту, рисуются линии, следующие за курсором мыши.

Реализация функции drag-and-drop

Классический паттерн использует три события: mousedown на элементе для начала перетаскивания, mousemove на document для отслеживания указателя (слушание на document, а не на элементе, означает, что перетаскивание продолжает работать, даже если указатель двигается быстрее блока), и mouseup для остановки.

<div>
<div id="draggable" style="width: 100px; height: 100px; background: blue; position: absolute; color: white; padding: 10px">    Drag me!
  </div>
</div>
<script>
  const draggable = document.getElementById('draggable');
  let active = false;
  let currentX;
  let currentY;
  let initialX;
  let initialY;

  draggable.addEventListener('mousedown', function(event) {
    active = true;
    const rect = draggable.getBoundingClientRect();
    initialX = event.clientX - rect.left;
    initialY = event.clientY - rect.top;
  });

  document.addEventListener('mouseup', function() {
    active = false;
  });

  document.addEventListener('mousemove', function(event) {
    if (active) {
      currentX = event.clientX - initialX;
      currentY = event.clientY - initialY;
      draggable.style.left = currentX + 'px';
      draggable.style.top = currentY + 'px';
    }
  });
</script>

Этот код создаёт простой перетаскиваемый синий квадрат на веб-странице:

  • JavaScript для перетаскивания:
    • Квадрат можно перемещать, кликая на нём и удерживая кнопку мыши. При нажатии (mousedown) запоминается место захвата и квадрат готовится к перемещению.
    • При отпускании кнопки мыши (mouseup) квадрат останавливается.
    • Пока кнопка мыши удерживается и вы перемещаете мышь (mousemove), квадрат следует за указателем по экрану, двигаясь туда, куда вы его тащите.

Улучшение удобства использования форм

Улучшение удобства форм за счёт интерактивных элементов, таких как иконки помощи, может значительно улучшить пользовательский опыт. Этот пример показывает простой и эффективный способ добавления динамического вспомогательного текста к полям формы.

<div>
  <p style="font-weight: bold;">Hover your mouse on the icon!</p>
    <label for="password">Password:</label>
    <input type="password" id="password" />
    <span id="helpIcon" style="cursor: help;">&#9432;</span>
    <div id="helpText" style="display:none; margin-top: 10px;">Use 8 or more characters with a mix of letters, numbers & symbols.</div>
</div>
<script>
    document.getElementById('helpIcon').addEventListener('mouseover', function() {
        document.getElementById('helpText').style.display = 'block';
    });

    document.getElementById('helpIcon').addEventListener('mouseout', function() {
        document.getElementById('helpText').style.display = 'none';
    });
</script>

Этот код обеспечивает функцию помощи для поля ввода пароля на веб-странице:

  • Поле пароля и иконка помощи: рядом с полем расположены метка, поле ввода пароля и иконка помощи.
  • JavaScript для отображения вспомогательного текста:
    • Когда вы наводите мышь на иконку (mouseover), под ней появляется скрытое сообщение с советами по созданию надёжного пароля.
    • Когда вы убираете мышь от иконки (mouseout), сообщение скрывается.

Примечание о доступности

События мыши срабатывают только для пользователей указывающих устройств. Пользователи клавиатуры, программ чтения с экрана и сенсорных устройств не будут вызывать mouseover, mousemove или обработчики правого клика. Для всего важного сочетайте обработчики мыши с их доступными аналогами:

  • Добавляйте слушатели focus/blur вместе с mouseenter/mouseleave, чтобы эффект также работал при переходе на элемент с клавиатуры.
  • Добавляйте keydown (Enter/Space) вместе с click для пользовательских виджетов, которые не являются нативными кнопками.
  • Никогда не скрывайте важный контент только за наведением.

Полную картину см. в разделе Соображения доступности DOM.

Заключение

События мыши JavaScript предлагают надёжный набор инструментов для создания интерактивного веб-опыта — от простого click до пользовательских контекстных меню, рисования на canvas и drag-and-drop. Ключи к их грамотному использованию: выбирайте правильное событие (mouseenter vs mouseover), читайте правильные координаты (clientX vs pageX vs offsetX) из объекта события, держите обработчики mousemove лёгкими и всегда предоставляйте доступную с клавиатуры альтернативу. При соблюдении этих правил события мыши становятся надёжной основой для создания привлекательных интерфейсов.

Практика

Практика
Какие из перечисленных являются типами событий мыши в JavaScript?
Какие из перечисленных являются типами событий мыши в JavaScript?
Was this page helpful?