VImage
Основной компонент. Объединяет ленивую загрузку, плейсхолдер, переключение форматов и переходы в одном элементе.
vue
<VImage
src="/photo.jpg"
alt="Описание"
:width="1200"
:height="600"
blurhash="LEHV6nWB2yk8pyo0adR*.7kCMdnj"
placeholder="data:image/jpeg;base64,..."
:widths="[400, 800, 1200]"
sizes="(max-width: 768px) 100vw, 50vw"
:lazy="true"
root-margin="300px"
fit="cover"
@load="onLoad"
@error="onError"
>
<template #error>
<div class="my-error">Image failed to load</div>
</template>
</VImage>Пропы
| Проп | Тип | По умолчанию | Описание |
|---|---|---|---|
src | string | SrcSet | — | URL или объект с вариантами форматов. Опционален, если задан image |
image | ImageMeta | — | Метаданные, вычисленные на этапе сборки (запись из манифеста CLI или импорт ?vik) — задаёт src/width/height/blurhash/thumbhash/placeholder/sizes. Любой явно указанный проп выше переопределяет соответствующее поле |
alt | string | — | Обязателен. Атрибут alt на <img>. В dev-сборках подозрительное значение (пустое, состоящее только из пробелов, или похожее на имя файла вроде "photo.jpg") логирует console.warn — осознанный alt="" для декоративного изображения никогда его не вызывает |
width | number | — | Собственная ширина; используется для резервирования пространства под aspect-ratio |
height | number | — | Собственная высота; используется для резервирования пространства под aspect-ratio |
blurhash | string | — | Строка BlurHash; декодируется в canvas внутри onMounted |
thumbhash | string | — | Строка ThumbHash; декодируется в PNG data URL, используется как blur-up плейсхолдер |
placeholder | string | — | Base64 LQIP или ThumbHash data URL; переопределяет thumbhash, если заданы оба |
placeholderMode | 'blur' | 'color' | 'shimmer' | 'blur' | 'color' показывает сплошной средний цвет (из thumbhash); 'shimmer' показывает анимированный скелетон (хэш не нужен) |
placeholderColor | string | — | Явный сплошной CSS-цвет плейсхолдера; имеет приоритет и не требует декодирования |
widths | number[] | — | Ширины в пикселях для автоматической генерации srcset на основе ширины (w) |
densities | number[] | Record<number, string> | — | Дескрипторы плотности (1x/2x/3x) для изображений фиксированного размера. Список переиспользует src; объект даёт отдельный файл на плотность. Имеет приоритет над widths, игнорирует sizes |
sizes | string | — | Атрибут sizes, передаваемый в <img> (только для srcset на основе ширины) |
breakpoints | BreakpointMap | — | Локальные брейкпоинты (сливаются с глобальными брейкпоинтами плагина) |
sources | ResponsiveSrc | — | Объект брейкпоинт → URL (или { avif?, webp?, fallback }) для арт-дирекции, опционально комбинируемый с переключением формата на брейкпоинт |
lazy | boolean | true | Включить ленивую загрузку через IntersectionObserver |
rootMargin | string | "200px" | rootMargin для IO — насколько раньше вьюпорта начинается загрузка |
threshold | number | 0 | threshold для IO — требуемая доля пересечения для срабатывания |
fit | ObjectFit | "cover" | Значение CSS object-fit на <img> |
focal | FocalPoint | — | Фокальная точка { x, y } (доли 0–1) → object-position; сохраняет объект в кадре, когда fit="cover" обрезает изображение |
maxRetries | number | 0 | Максимум попыток повтора при неудаче загрузки |
retryDelay | number | 1000 | Начальная задержка в мс; удваивается на каждом повторе (экспоненциальная задержка) |
fetchpriority | 'high' | 'low' | 'auto' | — | Подсказка браузеру о приоритете загрузки |
decoding | 'async' | 'sync' | 'auto' | 'async' | Режим декодирования изображения |
priority | boolean | false | Сокращение для LCP/hero-изображения — форсирует lazy=false, fetchpriority='high', decoding='sync'. Не автоматическое определение LCP (это ненадёжно до отрисовки) — отметьте именно то изображение, которое важно, вместо ручной установки трёх пропов |
respectSaveData | boolean | false | На соединении с экономией трафика: нейтрализует priority (остаётся lazy) и понижает src до наименьшего доступного URL из densities/image.srcset. См. Адаптация к сети |
layout | 'fixed' | 'responsive' | 'fill' | — | Пресет размещения обёртки. Если не задан, сохраняется текущее поведение по умолчанию (заполняет ширину контейнера, aspect-ratio сохраняется). См. Пресеты раскладки |
cdn | boolean | AutoLoaderConfig | — | Опционально: пропускает строковый src через autoLoader() — определяет CDN по URL и переписывает его, без ручной настройки адаптера. См. Автоопределение CDN с VImage |
loader | 'server' | — | Опционально: пропускает строковый src через обработчик vue-image-kit/server по запросу, используя buildImageUrl(). См. Подключение VImage к нему |
loaderRoute | string | /_vik/image | Переопределение маршрута для loader="server" — имеет приоритет над значением по умолчанию serverRoute плагина/модуля Nuxt |
События
| Событие | Payload | Описание |
|---|---|---|
@load | Event | Срабатывает при завершении загрузки изображения |
@error | Event | Срабатывает при неудаче загрузки изображения |
Слоты
| Слот | Описание |
|---|---|
#error | Кастомный UI, показываемый при неудаче загрузки. Если не задан, показывается серый прямоугольник с иконкой битого изображения. |
Примеры
Простое изображение с ленивой загрузкой:
vue
<VImage src="/photo.jpg" alt="Landscape" />С blurhash и размерами для резервирования aspect-ratio:
vue
<VImage
src="/photo.jpg"
alt="Landscape"
:width="1200"
:height="800"
blurhash="LEHV6nWB2yk8pyo0adR*.7kCMdnj"
/>WebP/AVIF с srcset и blur-up:
vue
<VImage
:src="{ avif: '/photo.avif', webp: '/photo.webp', fallback: '/photo.jpg' }"
alt="Product"
:width="800"
:height="600"
placeholder="data:image/jpeg;base64,/9j/4AAQSkZJRgAB..."
:widths="[400, 800]"
sizes="(max-width: 640px) 100vw, 800px"
/>Отключение ленивой загрузки для изображений над первым экраном:
vue
<VImage src="/hero.jpg" alt="Hero" :lazy="false" />LCP/hero-изображение — priority вместо трёх отдельных пропов:
vue
<VImage src="/hero.jpg" alt="Hero" :width="1600" :height="900" priority />Из вывода CLI/манифеста — без ручной настройки пропов:
vue
<script setup lang="ts">
import meta from './photo.jpg?vik' // или: import { images } from './assets/images'
</script>
<template>
<!-- src/width/height/blurhash/thumbhash/placeholder/sizes — всё из meta -->
<VImage :image="meta" alt="Product photo" />
</template>Фокальная точка — сохранить объект в кадре при обрезке:
vue
<!-- При fit="cover" изображение обрезается под рамку; focal определяет,
какая часть выживает. { x: 0.5, y: 0.3 } отдаёт приоритет верхней середине (например, лицу). -->
<VImage
src="/portrait.jpg"
alt="Team member"
:width="400"
:height="400"
fit="cover"
:focal="{ x: 0.5, y: 0.3 }"
/>Самый дешёвый плейсхолдер — сплошной средний цвет (без canvas, 0 байт):
vue
<!-- Режим 'color' берёт средний RGBA прямо из заголовка ThumbHash. -->
<VImage
src="/photo.jpg"
alt="Gallery item"
:width="600"
:height="400"
thumbhash="3OcRJYB4d3h/iIeHeEh3eIhw+j5n"
placeholder-mode="color"
/>
<!-- Или явный цвет, который вы уже знаете — ThumbHash вообще не нужен. -->
<VImage src="/photo.jpg" alt="Banner" placeholder-color="#1e3a8a" />Анимированный скелетон — когда хэша нет вообще:
vue
<!-- CSS shimmer-переход до загрузки изображения. Учитывает prefers-reduced-motion. -->
<VImage src="/photo.jpg" alt="Card" :width="400" :height="300" placeholder-mode="shimmer" />Кастомный слот ошибки:
vue
<VImage src="/missing.jpg" alt="Missing">
<template #error>
<div class="placeholder">
<span>📷</span>
<p>Image unavailable</p>
</div>
</template>
</VImage>Обработка событий:
vue
<script setup lang="ts">
function onLoad(e: Event) {
console.log('Image loaded', e)
}
function onError(e: Event) {
console.warn('Image failed', e)
}
</script>
<template>
<VImage src="/photo.jpg" alt="Photo" @load="onLoad" @error="onError" />
</template>