InView
Framework-agnostic движки для скролла, видимости элементов и их позиции относительно viewport — с адаптерами для Vue 3, Nuxt и React, работающими на одном общем цикле requestAnimationFrame и общем пуле IntersectionObserver.
Возможности
- Отслеживание скролла — позиция, направление, прогресс и скорость скролла окна или элемента, всё вычисляется на одном общем rAF-цикле вместо отдельного цикла на каждого подписчика.
- Отслеживание видимости — реактивная видимость элемента на базе
IntersectionObserverс определением стороны появления/исчезновения и режимом однократного срабатывания. Обсерверы пулятся по(root, rootMargin, threshold)— много элементов с одинаковыми настройками используют один общий обсервер. - Позиция элемента во viewport — прямоугольник элемента, насколько он уже прошёл через область видимости (
viewportProgress, 0..1) и расстояние от центра viewport — именно та геометрия, которая нужна reveal-эффекту или индикатору прогресса, уже вычисленная. Измеряется относительно скроллящегося контейнера вместо окна через опциюroot. - Примитив параллакс-слоя — превращает
viewportProgressв CSS-трансформацию с настраиваемой скоростью, осью, ограничением на краях и кривой плавности, и сам отключается приprefers-reduced-motion. - Scroll spy —
createScrollSpyотслеживает, какой из списка целевых элементов сейчас находится в полосе у центра viewport, и сообщает его индекс — стандартный приём подсветки навигации (сайдбар документации, оглавление), на том же пулящемся обсервере, что и всё остальное. - SSR-safe везде — каждый движок и каждый composable/хук возвращает статичный no-op снапшот, если нет
window, и запускает реальную подписку, как только оказывается на клиенте — никакой обёртки<ClientOnly>не требуется. - Адаптеры для Vue, Nuxt и React поверх одного ядра —
useScroll,useElementVisibility,useElementViewportиuseParallaxLayerсуществуют как Vue-composables, как авто-импортируемые composables в Nuxt и как React-хуки с тем же API и поведением — все три построены на одних и тех же framework-agnostic движках. - Reveal-эффекты в масштабе, без ручной привязки к каждому элементу —
createRevealControllerсканирует DOM по селектору (по умолчанию[data-reveal], .reveal) и переключает класс/атрибут по мере попадания элементов во viewport, включая добавленные позже — подхватывает их черезMutationObserver. Любую опцию можно переопределить на конкретном элементе черезdata-reveal-*атрибут, аobserve()/unobserve()добавляют элементы напрямую, минуя скан по селектору. У Vue и React есть обёртка жизненного циклаuseRevealController; у Vue дополнительно — директиваv-revealи renderless-компонент<InView>, у React — свой render-prop компонент<InView>, хукuseRevealи<InviewProvider>для значений по умолчанию на уровне приложения.staggerDelayвычисляет CSS-задержку для сгруппированного стаггера, с опциональным зацикленным режимом для длинных списков, и полностью пропускается приprefers-reduced-motion. - Маленькие реактивные утилиты —
useScrollTo/scrollToElementплавно скроллят контейнер так, чтобы элемент оказался у его края, со смещением;usePrefersReducedMotionпревращает статичную проверкуprefers-reduced-motionв живое значение, обновляющееся на событиеchangeмедиа-запроса;useStagger— реактивная обёртка вокругstaggerDelay. - Каждый адаптер реэкспортирует всё ядро —
@macrulez/inview-vueи@macrulez/inview-reactреэкспортируют всё из@macrulez/inview-core, а@macrulez/inview-nuxtавто-импортирует это же — так что для движков вродеcreateRevealControllerникогда не нужна отдельная установка@macrulez/inview-core.
Как это работает
Пакет — это четыре npm-пакета, объединённые одной архитектурой: framework-agnostic ядро (@macrulez/inview-core) делает всю реальную работу — отслеживание скролла, пулинг IntersectionObserver, батчинг через rAF — вообще без зависимости от фреймворка. @macrulez/inview-vue оборачивает каждый движок ядра в реактивный composable (рефы на входе, рефы на выходе). @macrulez/inview-react оборачивает те же движки ядра в хуки на базе useSyncExternalStore, зеркаля API Vue-composables 1:1, но с обычными значениями вместо рефов. @macrulez/inview-nuxt — тонкий модуль Nuxt поверх Vue-пакета: авто-импортирует каждый composable, утилиту и движок ядра, регистрирует директиву v-reveal глобально и применяет SSR-safe значения по умолчанию из nuxt.config.ts на клиенте.
Единственное, что нужно выбрать, — это адаптер: поставить @macrulez/inview-vue для Vue (или дать @macrulez/inview-nuxt подтянуть его самостоятельно), либо @macrulez/inview-react для React. Сами движки и опции/поведение, которые они дают, в обоих случаях остаются одинаковыми.