Компонент PlaceholderImage
<PlaceholderImage> из hazehash-vue показывает изображение поверх его плейсхолдера HazeHash: резервирует место с правильным соотношением сторон, рисует размытое превью в canvas и плавно проявляет настоящий <img> поверх него, когда тот загрузится.
<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 внутри.
Слоты
Нет.
Пример — хеши из ваших данных:
<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 или ячейку сетки. Высота берётся из соотношения сторон. Скруглённые углы работают, потому что корень обрезает содержимое:
<PlaceholderImage class="avatar" :hash="hash" :src="url" :width="64" :height="64" alt="" />.avatar {
width: 64px;
border-radius: 50%;
}Требования
hazehash-vue требует Vue 3.3 или новее и hazehash как peer-зависимости; см. Установка.