Skip to content

Директива v-reveal

v-reveal — переключает класс (по умолчанию "in") и/или data-атрибут на элементе-получателе по мере его появления во viewport, без самостоятельного вызова useElementVisibility(). Директива работает на уровне DOM, а не привязана к setup(), как composable, поэтому работает прямо внутри v-for — включая элементы, отрендеренные после асинхронного запроса, где composable на каждую итерацию не вызвать.

vue
<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 }". Для остального передайте объект:

vue
<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 в объекте-значении всегда побеждает, если указаны оба.

Пример:

vue
<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>
css
.reveal {
  opacity: 0;
  transition: opacity 0.3s;
}
.reveal.in {
  opacity: 1;
}

Когда лучше что-то другое

  • Один, уже известный элемент — обычный useElementVisibility() проще, если v-for не задействован.
  • Реактивное значение isVisible должно управлять чем-то бо́льшим, чем класс (например, условным монтированием тяжёлого дочернего компонента) — см. <InView>, он отдаёт значение через scoped-слот.
  • Целая страница (или контейнер) разметки, которую вообще не хочется размечать директивой/composable поэлементно — см. Контроллер reveal-эффектов — один вызов, независимый от фреймворка, сам находит подходящие элементы, включая появившиеся позже.