Something went wrong. Try again.
[READ-ONLY] Mirror of https://github.com/sxzz/midden. Archive posts and media across platforms, with tenant accounts and Telegram access
Something went wrong. Try again.
1.3 kB · 68 lines
Vue
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869<script setup vapor lang="ts">import { shallowRef, watch } from 'vue'const props = withDefaults( defineProps<{ src: string; alt: string; loading?: 'lazy' | 'eager' }>(), { loading: 'lazy' },)const state = shallowRef<'loading' | 'ready' | 'error'>('loading')watch( () => props.src, () => { state.value = 'loading' },)</script>
<template> <span class="image-shell" :class="{ skeleton: state === 'loading' }" :aria-busy="state === 'loading'" > <img :key="src" :src="src" :alt="alt" :loading="loading" decoding="async" :class="{ pending: state !== 'ready' }" @load="state = 'ready'" @error="state = 'error'" /> <span v-if="state === 'error'" class="image-error" role="status" >图片加载失败</span > </span></template>
<style scoped>.image-shell { position: relative; display: block; overflow: hidden; border-radius: inherit; background: var(--fill);}.image-shell img { display: block; width: 100%; height: 100%; object-fit: inherit; border-radius: inherit;}.image-shell { min-height: 80px;}.image-shell img.pending { opacity: 0;}.image-error { position: absolute; inset: 0; display: grid; place-items: center; padding: 8px; font-size: 12px; color: var(--subtle);}</style>