События scroll и wheel

Время чтения: меньше 5 мин

Кратко

Секция статьи "Кратко"

scroll — это событие на HTML-элементе. Событие происходит, когда страница или элемент не входит на экран и пользователь её прокручивает. Способ прокрутки может быть любым — колесом мыши, кнопками клавиатуры, с помощью полосы прокрутки на экране.

Событие wheel происходит, когда пользователь прокручивает колесо мыши. При этом реального прокручивания может не происходить. Например, наша страница полностью помещается на экран, но пользователь пытается её прокрутить. В этом случае событие wheel будет происходить, а событие scroll — нет.

Событие wheel говорит о том, что пользователь пытается прокрутить страницу или элемент, а событие scroll говорит о том, что прокрутка реально происходит.

Как пишется

Секция статьи "Как пишется"

Стандартно с помощью addEventListener:

        
          
          // обрабатываем скролл на всей страницеdocument.addEventListener('scroll', function(event) {  // реагируем на событие  console.log(event);});// отловим все случаи, когда пользователь крутит колесо мыши// при наведенном на элемент курсореlet div = document.getElementsByTagName('div')[0];div.addEventListener('wheel', function(event) {  console.log(event);});
          // обрабатываем скролл на всей странице
document.addEventListener('scroll', function(event) {
  // реагируем на событие
  console.log(event);
});

// отловим все случаи, когда пользователь крутит колесо мыши
// при наведенном на элемент курсоре
let div = document.getElementsByTagName('div')[0];
div.addEventListener('wheel', function(event) {
  console.log(event);
});

        
        
          
        
      

Как понять

Секция статьи "Как понять"

Разницу между событиями можно понять на демо ниже. wheel происходит всегда когда пользователь крутит колесо мыши (или что-то его заменяющее), а scroll только при прокрутке:

Открыть демо в новой вкладке

Объект события scroll

Секция статьи "Объект события scroll"

scroll использует базовый элемент события, в котором отсутствует информация о скорости прокрутки и направлении.

Чтобы понять, насколько прокрутилась страница или элемент, этот элемент получают из DOM-дерева или ключевого слова this и запрашивают свойства scrollTop или scrollLeft.

        
          
          document.addEventListener('scroll', function() {  // получаем высоту элемента, на котором произошло событие  console.log(this.scrollTop);});
          document.addEventListener('scroll', function() {
  // получаем высоту элемента, на котором произошло событие
  console.log(this.scrollTop);
});

        
        
          
        
      

Объект события wheel

Секция статьи "Объект события wheel"

Так как прокрутки при wheel не происходит, объект события содержит информацию о направлении и «силе» прокрутки в свойствах:

  • deltaX — горизонтальная прокрутка. Значение — целое число:
    • отрицательное, если пользователь прокручивает влево;
    • 0 — если в этом направлении прокрутка не происходит
    • положительное при прокрутке вправо;
  • deltaY — вертикальная прокрутка. Значение — целое число:
    • отрицательное, если пользователь прокручивает вверх;
    • 0 — если в этом направлении прокрутка не происходит
    • положительное при прокрутке вниз;

Если элемент имеет полосу прокрутки, то обычно после события wheel происходит scroll (смотри пример выше). Этого можно избежать, вызвав метод события preventDefault.

        
          
          document.addEventListener('wheel', function(event) {  // останавливаем поведение по умолчанию, то есть прокрутку  event.preventDefault();});
          document.addEventListener('wheel', function(event) {
  // останавливаем поведение по умолчанию, то есть прокрутку
  event.preventDefault();
});

        
        
          
        
      

С помощью объекта события можно, например, перемещать элемент по экрану при прокрутке колеса мыши на десктопе. Чтобы посмотреть, как это работает, откройте демо в новой вкладке по ссылке внизу.

Открыть демо в новой вкладке

На практике

Секция статьи "На практике"

Николай Лопин

Секция статьи "Николай Лопин"

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

🛠 Избежать большого количества событий scroll можно, используя технику под названием throttling. Её смысл состоит в том, чтобы принимать следующее событие только после истечения некоторого промежутка времени.

        
          
          const throttle = (func, limit) => {  let lastFunc;  let lastRan;  return function() {    const context = this;    const args = arguments;    if (!lastRan) {      func.apply(context, args);      lastRan = Date.now();    } else {      clearTimeout(lastFunc);      lastFunc = setTimeout(function() {        if ((Date.now() - lastRan) >= limit) {          func.apply(context, args);          lastRan = Date.now();        }      }, limit - (Date.now() - lastRan));    }  }}// код будет срабатывать раз в 1 секундуdocument.addEventListener('scroll', throttle(function() {  return console.log('Hey! It is', new Date().toUTCString());}, 1000));
          const throttle = (func, limit) => {
  let lastFunc;
  let lastRan;
  return function() {
    const context = this;
    const args = arguments;
    if (!lastRan) {
      func.apply(context, args);
      lastRan = Date.now();
    } else {
      clearTimeout(lastFunc);
      lastFunc = setTimeout(function() {
        if ((Date.now() - lastRan) >= limit) {
          func.apply(context, args);
          lastRan = Date.now();
        }
      }, limit - (Date.now() - lastRan));
    }
  }
}

// код будет срабатывать раз в 1 секунду
document.addEventListener('scroll', throttle(function() {
  return console.log('Hey! It is', new Date().toUTCString());
}, 1000));