You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.12 05:30:37