7 июня 2022 г.

Мышь: колёсико, событие wheel

Материал на этой странице устарел, поэтому скрыт из оглавления сайта.

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

…Но, тем не менее, его использование может быть оправдано. Например, можно добавить дополнительные удобства для тех, у кого колёсико есть.

Отличия колёсика от прокрутки

Несмотря на то, что колёсико мыши обычно ассоциируется с прокруткой, это совсем разные вещи.

  • При прокрутке срабатывает событие onscroll – рассмотрим его в дальнейшем. Оно произойдёт при любой прокрутке, в том числе через клавиатуру, но только на прокручиваемых элементах. Например, элемент с overflow:hidden в принципе не может сгенерировать onscroll.
  • А событие wheel является чисто «мышиным». Оно генерируется над любым элементом при передвижении колеса мыши. При этом не важно, прокручиваемый он или нет. В частности, overflow:hidden никак не препятствует обработке колеса мыши.

Кроме того, событие onscroll происходит после прокрутки, а onwheelдо прокрутки, поэтому в нём можно отменить саму прокрутку (действие браузера).

Зоопарк wheel в разных браузерах

Событие wheel появилось в стандарте не так давно. Оно поддерживается Chrome 31+, IE9+, Firefox 17+.

До него браузеры обрабатывали прокрутку при помощи событий mousewheel (все кроме Firefox) и DOMMouseScroll, MozMousePixelScroll (только Firefox).

Самые важные свойства современного события и его нестандартных аналогов:

wheel
Свойство deltaY – количество прокрученных пикселей по вертикали. Существуют также свойства deltaX и deltaZ для других направлений прокрутки.
MozMousePixelScroll
Срабатывает, начиная с Firefox 3.5, только в Firefox. Даёт возможность отменить прокрутку и получить размер в пикселях через свойство detail, ось прокрутки в свойстве axis.
mousewheel
Срабатывает в браузерах, которые ещё не реализовали wheel. В свойстве wheelDelta – условный «размер прокрутки», обычно равен 120 для прокрутки вверх и -120 – вниз. Он не соответствует какому-либо конкретному количеству пикселей.

Чтобы кросс-браузерно отловить прокрутку и, при необходимости, отменить её, можно использовать все эти события.

Пример, включающий поддержку IE8-:

if (elem.addEventListener) {
  if ('onwheel' in document) {
    // IE9+, FF17+, Ch31+
    elem.addEventListener("wheel", onWheel);
  } else if ('onmousewheel' in document) {
    // устаревший вариант события
    elem.addEventListener("mousewheel", onWheel);
  } else {
    // Firefox < 17
    elem.addEventListener("MozMousePixelScroll", onWheel);
  }
} else { // IE8-
  elem.attachEvent("onmousewheel", onWheel);
}

function onWheel(e) {
  e = e || window.event;

  // wheelDelta не даёт возможность узнать количество пикселей
  var delta = e.deltaY || e.detail || e.wheelDelta;

  var info = document.getElementById('delta');

  info.innerHTML = +info.innerHTML + delta;

  e.preventDefault ? e.preventDefault() : (e.returnValue = false);
}

В действии:

Ошибка в IE8

В браузере IE8 (только версия 8) есть ошибка. При наличии обработчика mousewheel – элемент не скроллится. Иначе говоря, действие браузера отменяется по умолчанию.

Это, конечно, не имеет значения, если элемент в принципе не прокручиваемый.

Задачи

важность: 5

Сделайте так, чтобы при прокрутке колёсиком мыши над элементом, он масштабировался.

Масштабирование обеспечивайте при помощи свойства CSS transform:

// увеличение в 1.5 раза
elem.style.transform = elem.style.WebkitTransform = elem.style.MsTransform = 'scale(1.5)';

Результат в iframe:

Решение использует кросс-браузерный код назначения обработчика onwheel на элемент и style.transform.

Открыть решение в песочнице.

важность: 4

В большинстве браузеров если в процессе прокрутки textarea колёсиком мышки (или жестами) мы достигаем границы элемента, то прокрутка продолжается уже на уровне страницы (в Firefox при этом будет небольшая задержка перед продолжением прокрутки).

Иными словами, если в примере ниже вы попробуете прокрутить textarea вниз, то когда прокрутка дойдёт до конца – начнёт прокручиваться документ:

То же самое происходит при прокрутке вверх.

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

Для редактирования более оптимально, чтобы при прокрутке до конца textarea страница не «улетала» вверх и вниз.

Вот тот же документ, но с желаемым поведением textarea:

Задача:

  • Создать скрипт, который при подключении к документу исправлял бы поведение всех textarea, чтобы при прокрутке они не трогали документ.
  • Направление прокрутки – только вверх или вниз.
  • Редактор прокручивает только мышкой или жестами (на мобильных устройствах), прокрутку клавиатурой здесь рассматривать не нужно (хотя это и возможно).

Открыть песочницу для задачи.

Карта учебника

Комментарии

перед тем как писать…
  • Если вам кажется, что в статье что-то не так - вместо комментария напишите на GitHub.
  • Для одной строки кода используйте тег <code>, для нескольких строк кода — тег <pre>, если больше 10 строк — ссылку на песочницу (plnkr, JSBin, codepen…)
  • Если что-то непонятно в статье — пишите, что именно и с какого места.