scroll и wheel

События прокрутки экрана и колеса мыши.

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

Кратко

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

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

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

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

Как пишется

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

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

        
          
          document.addEventListener('scroll', function(event) {  console.log(event)})
          document.addEventListener('scroll', function(event) {
  console.log(event)
})

        
        
          
        
      

Отловим все случаи, когда пользователь крутит колесо мыши при наведённом на первый <div> курсоре:

        
          
          const div = document.getElementsByTagName('div')[0]div.addEventListener('wheel', function(event) {  console.log(event)})
          const 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))