Vue图片加载时Loading Spinner异常显示问题求助
问题描述
我希望在图片加载时显示Loading Spinner,但不知如何正确实现。目前控制台能正常打印isLoading的true和false值,但Spinner仍不显示;若移除isLoading=false的设置,Spinner会一直显示。
Vue组件代码
<template> <div class="KingOfMountain"> <Spinner v-if="isLoading"/> //// ERROR <div v-else class="container"> <div v-if="!isEndGameKing" class="choices"> <p id="score">{{ currentCountKing }}/{{ ALL_FILMS.length - 1 }} <p/> <div class="photos"> <div class="first__film"> <img :src="firstFilm.Poster" :alt="firstFilm.title" @click="chooseLeftFilm"> <p id="title--film">{{ firstFilm.title }}</p> </div> <div class="second__film"> <img :src="secondFilm.Poster" :alt="secondFilm.title" @click="chooseRightFilm"> <p id="title--film">{{ secondFilm.title }}</p> </div> </div> </div> <div v-else class="winner"> <p id="winner--title">Победитель</p> <img :src="firstFilm.Poster" :alt="firstFilm.title"> </div> </div> </div> </template> <script> import game from "@/mixins/game"; import Spinner from "@/components/Spinner/Spinner"; //all good in css . it works export default { name: "KingOfMountain", data() { return{ isLoading:false } }, components: {Spinner}, methods: { chooseLeftFilm() { this.isLoading=true this.redirectToResultKing() // it is method in mixins (all Good, it works) this.isLoading=false }, chooseRightFilm() { this.isLoading=true this.firstFilm = this.secondFilm; this.redirectToResultKing() // it is method in mixins (all Good, it works) this.isLoading=false } }, } </script>
若修改为以下代码,Spinner会一直显示:
chooseLeftFilm() { this.isLoading=true this.redirectToResultKing() // it is method in mixins (all Good, it works) },
混入代码
export default { methods: { updateFilm() { // Here i random take 2 images from Vuex and then them delete and etc... this.currentCountKing++; this.allFilmsKingCopy = this.allFilmsKingCopy.filter(val => val !== this.secondFilm) this.secondFilm = this.allFilmsKingCopy[Math.floor(Math.random() * this.allFilmsKingCopy.length)] }, redirectToResultKing() { if (this.currentCountKing === this.ALL_FILMS.length - 1) { this.isEndGameKing = true } else { this.updateFilm() } } }, computed: { ...mapGetters(['ALL_FILMS']), },
Vuex代码
export default { state: { films: [], }, actions: { async getFilms({commit}) { const data = await fetch(URL); const dataResponse = await data.json(); const films=dataResponse.data commit("setData", films) }, }, mutations: { setData(state, films) { state.films = films }, }, getters: { ALL_FILMS(state) { return state.films }, } }
解决方案
核心问题分析
- Vue响应式更新异步特性:设置
isLoading=true后立刻执行isLoading=false,Vue的DOM更新是异步队列处理的,Spinner还没来得及渲染就被隐藏,所以看不到效果。 - 错误的时机判断:当前代码在数据更新后立刻隐藏Spinner,但实际需要等待新图片加载完成后再隐藏,而非数据更新完成就隐藏。
具体修改步骤
1. 监听图片加载完成事件
在模板的img标签添加@load事件,触发图片加载完成后的逻辑:
<div class="first__film"> <img :src="firstFilm.Poster" :alt="firstFilm.title" @click="chooseLeftFilm" @load="onImageLoad"> <p id="title--film">{{ firstFilm.title }}</p> </div> <div class="second__film"> <img :src="secondFilm.Poster" :alt="secondFilm.title" @click="chooseRightFilm" @load="onImageLoad"> <p id="title--film">{{ secondFilm.title }}</p> </div>
2. 调整组件方法逻辑
移除方法中直接设置isLoading=false的代码,改为在图片加载完成后隐藏:
methods: { chooseLeftFilm() { this.isLoading = true this.redirectToResultKing() }, chooseRightFilm() { this.isLoading = true this.firstFilm = this.secondFilm; this.redirectToResultKing() }, onImageLoad() { // 简单场景下可加短暂延迟,确保DOM更新完成 setTimeout(() => { this.isLoading = false }, 100) } }
3. 多图片加载的严谨判断(可选)
如果需要确保两张图片都加载完成再隐藏Spinner,可添加状态变量跟踪:
data() { return { isLoading: false, leftImageLoaded: false, rightImageLoaded: false } }, methods: { chooseLeftFilm() { this.isLoading = true this.leftImageLoaded = false this.rightImageLoaded = false this.redirectToResultKing() }, chooseRightFilm() { this.isLoading = true this.leftImageLoaded = false this.rightImageLoaded = false this.firstFilm = this.secondFilm; this.redirectToResultKing() }, onLeftImageLoad() { this.leftImageLoaded = true this.checkAllImagesLoaded() }, onRightImageLoad() { this.rightImageLoaded = true this.checkAllImagesLoaded() }, checkAllImagesLoaded() { if (this.leftImageLoaded && this.rightImageLoaded) { this.isLoading = false } } }
对应模板修改:
<img :src="firstFilm.Poster" :alt="firstFilm.title" @click="chooseLeftFilm" @load="onLeftImageLoad"> <img :src="secondFilm.Poster" :alt="secondFilm.title" @click="chooseRightFilm" @load="onRightImageLoad">
额外提示
- 若
updateFilm中有异步操作,需确保异步操作完成后再等待图片加载。 - 建议给Spinner添加全屏覆盖样式,避免用户重复点击,例如:
.spinner { position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0,0,0,0.5); display: flex; align-items: center; justify-content: center; z-index: 999; }
内容的提问来源于stack exchange,提问作者VueFrontend
相关产品推荐
相关产品推荐

