← Назад к вопросам

Как отловить событие прокрутки в JavaScript?

1.7 Middle🔥 191 комментариев
#JavaScript Core

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI3 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

События прокрутки (Scroll events)

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

Событие scroll на window

Самый простой способ — добавить слушатель события scroll на объект window:

// Базовый пример
window.addEventListener('scroll', function() {
  console.log('Страница прокручена!');
  console.log('Прокручено вверх на:', window.scrollY, 'пиксель');
  console.log('Видимое окно:', window.innerHeight, 'пиксель');
});

Позиция скролла

Для определения позиции скролла используются свойства:

window.addEventListener('scroll', () => {
  // window.scrollY или window.pageYOffset — вертикальная позиция
  console.log('Вертикальный скролл:', window.scrollY);

  // window.scrollX или window.pageXOffset — горизонтальная позиция
  console.log('Горизонтальный скролл:', window.scrollX);

  // Высота видимой области
  console.log('Высота окна:', window.innerHeight);

  // Общая высота документа
  console.log('Высота документа:', document.documentElement.scrollHeight);

  // Расстояние до конца страницы
  const distanceToBottom = document.documentElement.scrollHeight - (window.scrollY + window.innerHeight);
  console.log('До конца страницы:', distanceToBottom);
});

Проверка, прокручена ли страница вниз

window.addEventListener('scroll', () => {
  // Проверить, достигнут ли конец страницы
  const isAtBottom = window.scrollY + window.innerHeight >= document.documentElement.scrollHeight - 10;

  if (isAtBottom) {
    console.log('Пользователь достиг конца страницы!');
    // Загрузить ещё контент
  }
});

Ленивая загрузка изображений (Infinite Scroll)

window.addEventListener('scroll', () => {
  const distanceToBottom = document.documentElement.scrollHeight - (window.scrollY + window.innerHeight);

  if (distanceToBottom < 500) {
    loadMoreContent();
  }
});

function loadMoreContent() {
  console.log('Загружаю больше контента...');
  // Fetch запрос для получения новых данных
  fetch('/api/items?offset=20')
    .then(res => res.json())
    .then(data => renderItems(data));
}

Оптимизация производительности (Throttle/Debounce)

Событие scroll срабатывает очень часто (60+ раз в секунду), что может замедлить приложение. Используй debounce или throttle:

// Простой throttle
function throttle(func, limit) {
  let lastCall = 0;
  return function(...args) {
    const now = Date.now();
    if (now - lastCall > limit) {
      lastCall = now;
      func.apply(this, args);
    }
  };
}

const handleScroll = throttle(() => {
  console.log('Оптимизированный скролл:', window.scrollY);
}, 200); // срабатывает максимум раз в 200мс

window.addEventListener('scroll', handleScroll);

Scroll на конкретном элементе

Не только страница, но и отдельные элементы могут иметь прокрутку:

const container = document.querySelector('.scrollable-box');

container.addEventListener('scroll', () => {
  console.log('Скролл контейнера:', container.scrollTop);
  console.log('Ширина контейнера:', container.scrollLeft);
  console.log('Полная высота:', container.scrollHeight);

  // Проверить конец скролла в контейнере
  const isAtBottom = container.scrollTop + container.clientHeight >= container.scrollHeight - 10;
  if (isAtBottom) {
    console.log('Конец контейнера!');
  }
});

Плавная прокрутка к элементу

// Способ 1: scrollIntoView (современный)
const element = document.querySelector('#target');
element.scrollIntoView({ behavior: 'smooth', block: 'start' });

// Способ 2: Программно через window.scrollTo
window.scrollTo({
  top: 1000,
  behavior: 'smooth'
});

// Способ 3: Прокрутить к конкретному элементу
const header = document.querySelector('header');
header.scrollIntoView({ behavior: 'smooth' });

IntersectionObserver (современный подход)

Это более эффективный способ для отловки видимости элементов:

const observer = new IntersectionObserver((entries) => {
  entries.forEach(entry => {
    if (entry.isIntersecting) {
      console.log('Элемент видим:', entry.target);
      entry.target.classList.add('visible');

      // Загрузить изображение лениво
      if (entry.target.tagName === 'IMG') {
        entry.target.src = entry.target.dataset.src;
        observer.unobserve(entry.target);
      }
    }
  });
}, {
  threshold: 0.1 // срабатывает когда 10% элемента видимо
});

// Наблюдать за всеми элементами с классом lazy
document.querySelectorAll('.lazy-image').forEach(img => {
  observer.observe(img);
});

Практический пример: Header, реагирующий на скролл

const header = document.querySelector('header');
let lastScrollTop = 0;

window.addEventListener('scroll', () => {
  const currentScroll = window.scrollY;

  if (currentScroll > lastScrollTop) {
    // Скролл вниз — спрятать header
    header.classList.add('hidden');
  } else {
    // Скролл вверх — показать header
    header.classList.remove('hidden');
  }

  lastScrollTop = currentScroll;
});

React хук для обработки скролла

import { useEffect } from 'react';

export function useScroll(callback) {
  useEffect(() => {
    const handleScroll = () => {
      callback(window.scrollY);
    };

    window.addEventListener('scroll', handleScroll);
    return () => window.removeEventListener('scroll', handleScroll);
  }, [callback]);
}

// Использование
function MyComponent() {
  useScroll((scrollY) => {
    console.log('Текущий скролл:', scrollY);
  });

  return <div>Контент</div>;
}

Сравнение подходов

СпособПроизводительностьБраузерСложность
scroll событиеХорошо (с throttle)ВсеНизкая
IntersectionObserverОтличнаяСовременныеСредняя
requestAnimationFrameОтличнаяВсеСредняя
Scroll библиотекиПеременнаяВсеВысокая
Как отловить событие прокрутки в JavaScript? | PrepBro