Кратко
Секция статьи "Кратко"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));