Скролл-движок
createScrollEngine(target?, options?) — framework-agnostic скролл-движок для окна или прокручиваемого элемента. Батчит DOM-события скролла в один общий requestAnimationFrame-цикл и уведомляет подписчиков только тогда, когда вычисленное состояние реально изменилось.
function createScrollEngine(
target?: Window | HTMLElement,
options?: ScrollEngineOptions,
): ScrollEnginetarget по умолчанию — window на клиенте. Если window нет (серверный рендеринг) или target не передан вовсе, возвращается no-op движок со статичным нулевым состоянием вместо ошибки.
Опции
idleTimeout
number · по умолчанию: 150
Сколько миллисекунд бездействия скролла должно пройти, прежде чем isScrolling вернётся в false (а velocity сбросится в 0).
Возвращаемое значение
getState()
() => ScrollState
Синхронно читает текущее состояние, без подписки.
subscribe(callback)
(callback: (state: ScrollState) => void) => () => void
Сразу вызывает callback с текущим состоянием, затем — при каждом изменении. Возвращает функцию отписки.
scrollTo(position, options?)
(position: number | { x?: number; y?: number }, options?: ScrollToOptions) => void
Скроллит к позиции. Простое number задаёт вертикальный отступ (top). options.behavior по умолчанию 'smooth', если только prefersReducedMotion() не вернул true — тогда используется 'auto'.
destroy()
() => void
Убирает слушатель скролла, очищает таймер простоя, отписывается от общего rAF-цикла и очищает всех подписчиков.
ScrollState
Объект состояния, передаваемый в subscribe() и возвращаемый getState():
| Поле | Тип | Примечание |
|---|---|---|
x, y | number | Текущий отступ скролла. |
direction | 'up' | 'down' | 'left' | 'right' | null | Вычисляется из последней дельты скролла — меняется только при ненулевой дельте. |
progress | number | 0..1, по вертикальному диапазону скролла, если цель прокручивается по вертикали, иначе по горизонтальному, иначе 0. |
velocity | number | Пикселей за кадр, вычисляется по пройденному расстоянию между двумя тиками rAF. |
isScrolling | boolean | true пока идёт скролл, снова false через idleTimeout мс без скролла. |
Пример:
import { createScrollEngine } from '@macrulez/inview-core'
const scroll = createScrollEngine(window, { idleTimeout: 200 })
const unsubscribe = scroll.subscribe((state) => {
document.title = `${Math.round(state.progress * 100)}% прокручено`
})
// позже
scroll.scrollTo({ y: 0 })
unsubscribe()
scroll.destroy()Нужна реактивная версия? Смотрите Реактивное состояние скролла для Vue или React-хуки для React — оба оборачивают этот же движок.