Vue3如何实现相册卡片内所有图片加载完成后再显示组件
你当前的实现里isLoading仅在接口请求完成后就关闭了,但接口只返回图片的URL地址,图片资源本身的浏览器加载过程是在组件渲染后才触发的,这是出现逐步加载效果的核心原因。另外你现有代码的异步逻辑存在错误,fetch albums的后续then没有等待每个相册的图片接口请求完成,就提前把isLoading设为了false。
以下是两种可落地的实现方案:
方案1:等待所有相册的所有图片全部加载完成后,统一渲染所有卡片
第一步:新增图片预加载工具方法
// 预加载单张图片,加载成功/失败都resolve,避免单张图加载失败卡住整个渲染流程 preloadImage(url: string): Promise<void> { return new Promise((resolve) => { const img = new Image() img.src = url img.onload = () => resolve() img.onerror = () => resolve() }) }
第二步:重构getAlbums的异步逻辑
用Promise.all等待所有相册的图片接口请求完成、所有图片资源预加载完成后,再赋值相册列表、关闭加载状态:
async getAlbums() { this.isLoading = true; let id_param = this.$route.params.id; try { // 1. 请求相册列表 const albumRes = await fetch( `https://jsonplaceholder.typicode.com/albums/${ id_param === undefined ? "" : "?userId=" + id_param }` ) const albums: Album[] = await albumRes.json() // 2. 并行请求所有相册的缩略图列表 const albumsWithPhotos = await Promise.all( albums.map(async (album) => { const photos = await this.getRandomPhotos(album.id) return { ...album, thumbnailPhotos: photos } }) ) // 3. 收集所有需要预加载的图片URL,并行预加载 const allImageUrls = albumsWithPhotos.flatMap(album => album.thumbnailPhotos.map(photo => photo.thumbnailUrl) ) await Promise.all(allImageUrls.map(url => this.preloadImage(url))) // 4. 所有资源准备完成后赋值,触发批量渲染 this.albums = albumsWithPhotos } catch (err) { console.error('资源加载失败', err) } finally { this.isLoading = false } }
第三步:调整模板渲染条件
确保只有加载完成后才渲染相册列表:
<template> <div class="content-container"> <div v-if="isLoading" style="width: 100%">LOADING</div> <template v-else> <album-card v-for="album in albums" :key="album.id" :albumTitle="album.title" :albumId="album.id" :albumPhotos="album.thumbnailPhotos" ></album-card> </template> </div> </template>
方案2:每个相册卡片独立控制加载状态(更推荐,避免大量相册时等待时间过长)
可以把加载逻辑下沉到AlbumCard组件内部:
- AlbumCard内部新增
cardLoading状态,默认值为true - 组件接收
albumPhotos参数后,内部预加载所有传入的图片 - 全部加载完成后把
cardLoading设为false,显示卡片内容,否则显示卡片骨架屏/占位加载效果
这种方案不需要等所有相册加载完成,每个相册资源准备好就单独渲染,体验更流畅。
内容的提问来源于stack exchange,提问作者jckob
相关产品推荐
相关产品推荐

