Директива v-reveal
v-reveal — переключает класс (по умолчанию "in") и/или data-атрибут на элементе-получателе по мере его появления во viewport, без самостоятельного вызова useElementVisibility(). Директива работает на уровне DOM, а не привязана к setup(), как composable, поэтому работает прямо внутри v-for — включая элементы, отрендеренные после асинхронного запроса, где composable на каждую итерацию не вызвать.
<template>
<div v-for="item in items" :key="item.id" v-reveal.once class="card">
{{ item.title }}
</div>
</template>v-reveal.once — сокращение для v-reveal="{ once: true }". Для остального передайте объект:
<div v-reveal="{ once: true, threshold: 0.3, class: 'visible', onEnter: (info) => track(item.id) }">Свежий инлайн-объект опций при каждом перерендере — обычное дело, ведь v-reveal="{ once: true, onEnter: ... }" каждый раз строит новый литерал — не заставляет переподписываться: class/attribute/once/ threshold/rootMargin/root сравниваются по значению (threshold-массив — по содержимому, а не по ссылке), а идентичность onEnter/onLeave полностью игнорируется. Директива отвязывается и привязывается заново, только когда одно из этих значений реально изменилось.
Значение биндинга
class
string | null · по умолчанию: 'in'
Передайте null, чтобы полностью отключить переключение класса (например, если нужен только attribute).
attribute
string | null · по умолчанию: null
Булев data-атрибут, выставляется вместе с class (присутствует пока элемент пересекает viewport, иначе убирается) — для стилизации чисто по атрибуту.
once
boolean · по умолчанию: viewportDefaults.once, либо true, если указан модификатор .once
threshold
number | number[] · по умолчанию: viewportDefaults.threshold
rootMargin
string · по умолчанию: viewportDefaults.rootMargin
root
HTMLElement | null · по умолчанию: null
onEnter / onLeave
(info: IntersectionInfo) => void · по умолчанию: —
Та же форма IntersectionInfo, что и в Движке видимости.
Всё перечисленное выше берёт значение по умолчанию из viewportDefaults так же, как и useElementVisibility — настройте их один раз через setViewportDefaults() вместо повторения опций на каждом v-reveal.
Модификаторы
.once
Сокращение для once: true — эквивалент v-reveal="{ once: true }", но явный once в объекте-значении всегда побеждает, если указаны оба.
Пример:
<script setup lang="ts">
const cards = [{ id: 1, title: 'A' } /* ...рендерится через v-for, возможно после запроса */]
</script>
<template>
<div
v-for="card in cards"
:key="card.id"
v-reveal="{ once: true, threshold: 0.2 }"
class="reveal"
>
{{ card.title }}
</div>
</template>.reveal {
opacity: 0;
transition: opacity 0.3s;
}
.reveal.in {
opacity: 1;
}Когда лучше что-то другое
- Один, уже известный элемент — обычный
useElementVisibility()проще, еслиv-forне задействован. - Реактивное значение
isVisibleдолжно управлять чем-то бо́льшим, чем класс (например, условным монтированием тяжёлого дочернего компонента) — см.<InView>, он отдаёт значение через scoped-слот. - Целая страница (или контейнер) разметки, которую вообще не хочется размечать директивой/composable поэлементно — см. Контроллер reveal-эффектов — один вызов, независимый от фреймворка, сам находит подходящие элементы, включая появившиеся позже.