Vue中如何检测所有图片加载完成以设置isLoaded为true?
解决Vue中等待所有图片加载完成后再显示内容的问题
你遇到的问题确实是因为getElementsByClassName返回的是HTMLCollection(类数组对象),不能直接给整个集合绑定onload事件,必须遍历每个图片元素单独绑定。不过在Vue项目里,我们更推荐用Vue的响应式特性来处理,而不是直接操作DOM,这样更符合Vue的设计理念。
下面给你两种可行的方案:
方案一:通过图片的@load事件统计加载完成数量
这种方法最直接,利用Vue的事件绑定,在每张图片加载完成时触发计数,当所有图片都加载完成后再设置isLoaded为true。
修改后的代码:
<template> <div v-if='isLoaded'> <div @click='selectSight(index)' v-for='(sight, index) in sights' :key="index"> <!-- 给img绑定load和error事件,处理加载成功/失败的情况 --> <img :src="'https://maps.googleapis.com/maps/api/place/photo?maxwidth=300&photoreference=' + sight.photos[0].photo_reference + '&key=' + YOUR_API_KEY" @load="handleImageLoad" @error="handleImageLoad" > </div> </div> </template> <script> import axios from 'axios' export default { data(){ return { sights: null, isLoaded: false, loadedCount: 0, // 记录已加载完成的图片数量 YOUR_API_KEY: '你的Google API密钥' // 记得替换成你的真实密钥 } }, mounted() { axios.get('/getSights/' + this.lat + '/' + this.lng + '/' + this.type + '/' + this.range) .then(response => { this.sights = response.data.result.results this.nextPageToken = response.data.result.next_page_token // 重置计数器,避免多次请求时计数混乱 this.loadedCount = 0 }).catch((error) => console.log(error)); }, methods: { handleImageLoad() { this.loadedCount++ // 当已加载数量等于图片总数时,显示内容 if (this.loadedCount === this.sights?.length) { this.isLoaded = true } }, selectSight(index) { // 你的selectSight逻辑 } } } </script>
注意点:
- 一定要加上
@error事件,避免因为某张图片加载失败(比如链接无效)导致计数器永远达不到总数,页面一直不显示。 - 记得替换
YOUR_API_KEY为你的真实Google Places API密钥,否则图片无法加载。 - 给
v-for加上:key,符合Vue的最佳实践。
方案二:使用Vue的ref获取图片元素并绑定事件
如果你更倾向于操作DOM(不推荐,但可以作为备选),可以用Vue的ref获取所有图片元素,在sights数据更新后遍历绑定onload事件。
修改后的代码:
<template> <div ref="sightsContainer"> <div @click='selectSight(index)' v-for='(sight, index) in sights' :key="index"> <img :src="'https://maps.googleapis.com/maps/api/place/photo?maxwidth=300&photoreference=' + sight.photos[0].photo_reference + '&key=' + YOUR_API_KEY" class="sight-photos" > </div> </div> </template> <script> import axios from 'axios' export default { data(){ return { sights: null, isLoaded: false, YOUR_API_KEY: '你的Google API密钥' } }, mounted() { axios.get('/getSights/' + this.lat + '/' + this.lng + '/' + this.type + '/' + this.range) .then(response => { this.sights = response.data.result.results this.nextPageToken = response.data.result.next_page_token // 等待DOM更新后再获取图片元素 this.$nextTick(() => { this.bindImageLoadEvents() }) }).catch((error) => console.log(error)); }, methods: { bindImageLoadEvents() { const images = this.$refs.sightsContainer.querySelectorAll('.sight-photos') let loadedCount = 0 const totalImages = images.length images.forEach(img => { // 处理已经加载完成的图片(比如从缓存加载的) if (img.complete) { loadedCount++ checkAllLoaded() return } // 绑定加载事件 img.onload = () => { loadedCount++ checkAllLoaded() } // 绑定错误事件 img.onerror = () => { loadedCount++ checkAllLoaded() } }) function checkAllLoaded() { if (loadedCount === totalImages) { this.isLoaded = true } }.bind(this) }, selectSight(index) { // 你的selectSight逻辑 } } } </script>
注意点:
- 必须用
this.$nextTick(),因为Vue更新DOM是异步的,赋值sights后需要等待DOM渲染完成才能获取到图片元素。 - 要判断
img.complete,因为有些图片可能从浏览器缓存加载,不会触发onload事件,直接标记为已加载。
两种方案里,方案一更符合Vue的响应式开发思路,代码更简洁,也更容易维护,推荐你使用。
内容的提问来源于stack exchange,提问作者Onyx
相关产品推荐
相关产品推荐

