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

如何避免页面刷新时重复调用v-img组件加载同一图片?

实现图片仅加载一次(含刷新页面场景)

要让图片仅加载一次,即使刷新页面也不重复请求,可从浏览器缓存、前端手动缓存、状态管理缓存三个方向实现,以下是具体方案:


1. 利用浏览器HTTP缓存(推荐优先使用)

浏览器默认会对静态资源(包括图片)做缓存,只要服务器给图片资源配置合适的响应头,刷新页面时浏览器会直接读取本地缓存,不会发起重复请求。

关键响应头配置

服务器需返回以下类型的响应头(以Nginx为例):

location ~* \.(jpeg|jpg|png)$ {
    expires 1y;  # 缓存1年
    add_header Cache-Control "public, max-age=31536000";
    add_header ETag $file_modified;  # 资源变更验证标识
}

配置后,浏览器首次加载图片会缓存到本地,后续刷新或重新打开页面时,只要缓存未过期就直接用本地副本;过期后会通过ETag验证资源是否更新,仅在资源变化时才重新下载。


2. 前端手动缓存(适用于需精细控制的场景)

如果无法控制服务器配置,或需要强制本地缓存,可将图片转成Blob存储到localStorage,下次加载直接读取本地缓存生成URL。

组件内实现示例

<template>
  <v-img
    height="450"
    :src="cachedImageSrc"
    :lazy-src="cachedLazyImageSrc"
    class="d-none d-md-block"
    alt="001"
  ></v-img>
</template>

<script>
export default {
  data() {
    return {
      originalSrc: 'https://images.pexels.com/photos/10480463/pexels-photo-10480463.jpeg?auto=compress&cs=tinysrgb&w=1260&h=750&dpr=1',
      originalLazySrc: 'https://images.pexels.com/photos/10877192/pexels-photo-10877192.jpeg',
      cachedImageSrc: '',
      cachedLazyImageSrc: ''
    }
  },
  async mounted() {
    this.cachedImageSrc = await this.cacheImage(this.originalSrc)
    this.cachedLazyImageSrc = await this.cacheImage(this.originalLazySrc)
  },
  methods: {
    async cacheImage(url) {
      const cacheKey = `image_${btoa(url)}`
      const cachedBase64 = localStorage.getItem(cacheKey)
      
      // 存在缓存则直接生成Blob URL
      if (cachedBase64) {
        const blob = new Blob([Uint8Array.from(atob(cachedBase64), c => c.charCodeAt(0))])
        return URL.createObjectURL(blob)
      }
      
      // 无缓存则请求图片并存储
      const response = await fetch(url)
      const blob = await response.blob()
      
      return new Promise(resolve => {
        const reader = new FileReader()
        reader.onloadend = () => {
          const base64Str = reader.result.split(',')[1]
          localStorage.setItem(cacheKey, base64Str)
          resolve(URL.createObjectURL(blob))
        }
        reader.readAsDataURL(blob)
      })
    }
  },
  beforeUnmount() {
    // 释放Blob URL,避免内存泄漏
    URL.revokeObjectURL(this.cachedImageSrc)
    URL.revokeObjectURL(this.cachedLazyImageSrc)
  }
}
</script>

注意事项

  • localStorage有存储上限(通常为5MB),不适合缓存大尺寸图片;
  • 页面卸载时需调用URL.revokeObjectURL释放Blob资源,避免内存泄漏。

3. 结合状态管理缓存(多组件共享场景)

如果图片资源需要在多个组件间共享,可将缓存逻辑放到Vuex/Pinia中,配合asyncData(Nuxt场景)实现页面刷新后仍能复用缓存。

Pinia缓存模块示例

// stores/imageCache.js
import { defineStore } from 'pinia'

export const useImageCacheStore = defineStore('imageCache', {
  state: () => ({
    images: {}
  }),
  actions: {
    async fetchAndCache(url) {
      const cacheKey = `image_${btoa(url)}`
      
      // 优先读取内存缓存
      if (this.images[cacheKey]) return this.images[cacheKey]
      
      // 内存无缓存则读取localStorage持久化缓存
      const cachedBase64 = localStorage.getItem(cacheKey)
      if (cachedBase64) {
        const blob = new Blob([Uint8Array.from(atob(cachedBase64), c => c.charCodeAt(0))])
        const blobUrl = URL.createObjectURL(blob)
        this.images[cacheKey] = blobUrl
        return blobUrl
      }
      
      // 无缓存则请求资源并存储
      const response = await fetch(url)
      const blob = await response.blob()
      const blobUrl = URL.createObjectURL(blob)
      
      // 转base64存入localStorage持久化
      const reader = new FileReader()
      reader.onloadend = () => {
        const base64Str = reader.result.split(',')[1]
        localStorage.setItem(cacheKey, base64Str)
      }
      reader.readAsDataURL(blob)
      
      this.images[cacheKey] = blobUrl
      return blobUrl
    }
  }
})

组件中使用(Nuxt asyncData场景)

<template>
  <v-img
    height="450"
    :src="cachedImageSrc"
    :lazy-src="cachedLazyImageSrc"
    class="d-none d-md-block"
    alt="001"
  ></v-img>
</template>

<script setup>
import { useImageCacheStore } from '~/stores/imageCache'

const imageCacheStore = useImageCacheStore()
const originalSrc = 'https://images.pexels.com/photos/10480463/pexels-photo-10480463.jpeg?auto=compress&cs=tinysrgb&w=1260&h=750&dpr=1'
const originalLazySrc = 'https://images.pexels.com/photos/10877192/pexels-photo-10877192.jpeg'

const cachedImageSrc = await imageCacheStore.fetchAndCache(originalSrc)
const cachedLazyImageSrc = await imageCacheStore.fetchAndCache(originalLazySrc)

onUnmounted(() => {
  URL.revokeObjectURL(cachedImageSrc)
  URL.revokeObjectURL(cachedLazyImageSrc)
})
</script>

内容的提问来源于stack exchange,提问作者MonLes

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.05 11:10:14