Видимость элемента
useElementVisibility(target, options?) — реактивная видимость элемента на базе IntersectionObserver. SSR-safe: наблюдение начинается, как только target разрешается в реальный элемент на клиенте.
function useElementVisibility(
target: MaybeRefOrGetter<HTMLElement | null | undefined>,
options?: UseElementVisibilityOptions,
): UseElementVisibilityReturnКаждый вызов использует один общий модульный инстанс createVisibilityEngine() — согласуется с собственным дизайном движка на пулящихся обсерверах.
Опции
threshold
MaybeRefOrGetter<number | number[] | undefined> · по умолчанию: viewportDefaults.threshold (0, если не переопределено)
Изменение этого значения как ref/геттера вызывает настоящую переподписку — членство в пуле привязано к нему, так же как к rootMargin/root.
rootMargin
MaybeRefOrGetter<string | undefined> · по умолчанию: viewportDefaults.rootMargin ('0px', если не переопределено)
То же поведение переподписки, что у threshold.
root
MaybeRefOrGetter<HTMLElement | null | undefined> · по умолчанию: null
То же поведение переподписки, что у threshold/rootMargin.
once
MaybeRefOrGetter<boolean | undefined> · по умолчанию: viewportDefaults.once (false, если не переопределено)
В отличие от threshold/rootMargin/root, изменение этого значения обновляет уже существующую подписку вживую — без переподписки, без пересоздания observer'а.
onEnter
(info: IntersectionInfo) => void · по умолчанию: —
onLeave
(info: IntersectionInfo) => void · по умолчанию: —
onEnter/onLeave осознанно остаются обычными значениями, не MaybeRefOrGetter — колбэк, замыкающий .value рефа, и так читает его заново при каждом вызове, поскольку composables в Vue выполняются один раз в setup(). Здесь просто нечего чинить обёрткой.
threshold/rootMargin/once берут значение по умолчанию из общего объекта viewportDefaults, а не из жёстко заданных 0/'0px'/false — см. setViewportDefaults() ниже и Модуль Nuxt — там описано, как это обычно настраивается на уровне приложения.
Возвращаемое значение
isVisible
Ref<boolean>
ratio
Ref<number>
Текущий intersectionRatio элемента.
Пример:
<script setup lang="ts">
import { ref } from 'vue'
import { useElementVisibility } from '@macrulez/inview-vue'
const card = ref<HTMLElement | null>(null)
const { isVisible } = useElementVisibility(card, { threshold: 0.5, once: true })
</script>
<template>
<div ref="card" :class="{ 'is-visible': isVisible }">...</div>
</template>Автоматически переподписывается при изменении target, threshold, rootMargin или root; once вместо этого обновляет уже существующую подписку вживую.
threshold/rootMargin/root/once принимают ref/геттер, а не только обычное значение:
<script setup lang="ts">
const stopOnceUserOptsIn = ref(false)
const { isVisible } = useElementVisibility(card, { once: stopOnceUserOptsIn })
// позже: stopOnceUserOptsIn.value = true — обновляется вживую, без переподписки
</script>Глобальные значения по умолчанию
setViewportDefaults() / viewportDefaults — общие для всего пакета значения по умолчанию для threshold/rootMargin/once, переопределяемые один раз на уровне приложения вместо передачи одних и тех же опций в каждое место вызова. Читаются и этим composable, и v-reveal, и <InView>.
interface ViewportDefaults {
threshold: number | number[]
rootMargin: string
once: boolean
}
const viewportDefaults: ViewportDefaults // { threshold: 0, rootMargin: '0px', once: false }
function setViewportDefaults(overrides: Partial<ViewportDefaults>): voidsetViewportDefaults() перезаписывает только те поля, что вы реально передали — она подмешивает их в общий объект viewportDefaults, а не заменяет его целиком. Именно это под капотом вызывает @macrulez/inview-nuxt из своих опций модуля.