Skip to content

Компонент PlaceholderImage ​

<PlaceholderImage> из hazehash-vue показывает изображение поверх его плейсхолдера HazeHash: резервирует место с правильным соотношением сторон, рисует размытое превью в canvas и плавно проявляет настоящий <img> поверх него, когда тот загрузится.

vue
<script setup lang="ts">
import { PlaceholderImage } from 'hazehash-vue'
</script>

<template>
  <PlaceholderImage
    hash="Ed7UwRWKKv5znm6a7sC1tziHDNpMuCikxrYpIg"
    src="/photo.jpg"
    alt="Mountain lake"
    :width="1280"
    :height="959"
  />
</template>

Компонент только рисует хеши. Создайте их заранее командой hazehash encode или хелперами для Node.js, либо дайте модулю Nuxt сгенерировать их при сборке.

Как он рендерится ​

  • На сервере — <div> с position: relative, overflow: hidden, средним цветом хеша в background-color и соотношением сторон в aspect-ratio, а внутри настоящий <img>. Canvas нет, поэтому серверная разметка и первый клиентский рендер одинаковы, и расхождения при гидрации невозможны.
  • После монтирования — добавляется <canvas aria-hidden="true"> с размытым превью, заполняющий рамку, а настоящая картинка плавно проявляется поверх него, когда срабатывает её событие load. Изображение, которое уже было в кэше до гидрации, определяется через img.complete, поэтому оно появляется сразу, а не ждёт события, которое уже произошло.
  • Соотношение сторон — если заданы и width, и height, они определяют пропорции, иначе пропорции берутся из хеша. При известных пропорциях картинка заполняет рамку через object-fit: cover, без них показывается в естественных пропорциях.
  • Уменьшенное движение — при prefers-reduced-motion: reduce плавное проявление отключается.
  • Недопустимый хеш — исключение не бросается. Рамка остаётся с плоским фоном, а в консоль один раз за страницу выводится предупреждение [hazehash-vue] invalid placeholder hash:.

Пропсы ​

hash ​

string · по умолчанию: undefined

Хеш изображения в виде строки base64url. Без него компонент рендерит только <img>. В Nuxt, если hash не задан, модуль ищет его по src.

src ​

string · по умолчанию: undefined

URL настоящего изображения. Без него рендерится только плейсхолдер.

alt ​

string · по умолчанию: ''

Текст alt изображения. Canvas скрыт от вспомогательных технологий, поэтому озвучивается только настоящая картинка; для декоративного изображения оставьте alt пустым.

width ​

number | string · по умолчанию: undefined

Собственная ширина изображения. Вместе с height задаёт соотношение сторон рамки и передаётся в <img>.

height ​

number | string · по умолчанию: undefined

Собственная высота изображения.

size ​

number · по умолчанию: 32

Длинная сторона декодированного превью в пикселях, ограниченная диапазоном 4–128, как и опция size у decode().

fade ​

number · по умолчанию: 300

Длительность плавного проявления настоящего изображения в миллисекундах. 0 показывает изображение без перехода.

События ​

Нет. <img> обрабатывает своё событие load внутри.

Слоты ​

Нет.

Пример — хеши из ваших данных:

vue
<script setup lang="ts">
import { PlaceholderImage } from 'hazehash-vue'

defineProps<{
  photos: { url: string; hash: string; width: number; height: number; title: string }[]
}>()
</script>

<template>
  <PlaceholderImage
    v-for="photo in photos"
    :key="photo.url"
    :src="photo.url"
    :hash="photo.hash"
    :width="photo.width"
    :height="photo.height"
    :alt="photo.title"
  />
</template>

Стилизация ​

Корневой <div> это обычный блок, поэтому он принимает любые атрибуты, включая class и style. Размеры задавайте на нём: ширину, max-width или ячейку сетки. Высота берётся из соотношения сторон. Скруглённые углы работают, потому что корень обрезает содержимое:

vue
<PlaceholderImage class="avatar" :hash="hash" :src="url" :width="64" :height="64" alt="" />
css
.avatar {
  width: 64px;
  border-radius: 50%;
}

Требования ​

hazehash-vue требует Vue 3.3 или новее и hazehash как peer-зависимости; см. Установка.