Vue中图片懒加载不生效,是写法有问题吗?

轩辕艳青 阅读 55

我在用 Vue 3 做一个图片列表页,想用原生 Intersection Observer 实现懒加载,但滚动时图片根本没触发加载,一直显示 loading 占位图。我查了文档也加了 rootMargin,但还是不行。

下面是我组件里的一段代码,是不是哪里写错了?

<template>
  <img 
    v-for="item in images" 
    :key="item.id"
    :data-src="item.url"
    src="loading.gif"
    class="lazy"
    @load="onImageLoad"
  />
</template>

<script setup>
// 省略部分逻辑,observer 在 onMounted 里初始化
</script>
我来解答 赞 8 收藏
二维码
手机扫码查看
2 条解答
智玲
智玲 Lv1
当时我也卡在懒加载这里,搞了半天才发现几个关键点。首先你的 data-src 属性没问题,但 Intersection Observer 的初始化和使用要注意。

你得确认 observer 实例确实绑定了每个图片元素。我给你个完整的代码片段参考:


let observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
let img = entry.target
img.src = img.getAttribute('data-src')
observer.unobserve(img)
}
})
}, { rootMargin: '0px 0px 100px 0px' })

onMounted(() => {
const imgs = document.querySelectorAll('.lazy')
imgs.forEach(img => {
observer.observe(img)
})
})


注意两点:第一,observer 需要在 onMounted 生命周期钩子中初始化;第二,观察者需要绑定到具体元素上。我当时就忘了这步,结果怎么都不触发加载。

另外检查一下你的 loading 占位图路径是否正确,有时候问题可能出在简单的路径错误上。记得测试时用网络调试工具看看请求有没有发出去。这些问题搞定了,懒加载基本就能正常工作了。
点赞
2026-03-29 17:07
上官广利
这问题的关键是你漏了 IntersectionObserver 的核心实现部分啊,代码里只看到了模板部分。我来详细说下完整解决方案。

首先,懒加载的原理是通过 IntersectionObserver 监测图片是否进入视口,然后替换 src 属性。你现在的代码有两个主要问题:

1. 缺少实际的观察逻辑
2. 图片加载事件绑定在了占位图上,这完全没用

正确的做法应该是这样:

// 在 setup 里
import { onMounted } from 'vue'

const images = ref([...]) // 你的图片数据
let observer

onMounted(() => {
// 创建观察器
observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
const img = entry.target
img.src = img.dataset.src
observer.unobserve(img) // 加载后取消观察
}
})
}, {
rootMargin: '200px' // 提前200px加载
})

// 观察所有懒加载图片
document.querySelectorAll('.lazy').forEach(img => {
observer.observe(img)
})
})


模板部分可以保持原样,但要确保:
1. 所有懒加载图片都有 lazy
2. 真实图片地址放在 data-src,不要直接放 src
3. 移除那个没用的 @load 事件

另外提醒下,现代浏览器其实已经支持原生懒加载了,加个 loading="lazy" 属性就行:
<img src="real.jpg" loading="lazy">
不过如果你需要兼容旧浏览器或者要更精细控制,用 IntersectionObserver 还是必要的。

对了,记得在组件卸载时清理观察器:
onUnmounted(() => {
observer.disconnect()
})


这代码我上周刚在项目里用过,实测有效。你遇到的应该是没正确初始化观察器的问题。
点赞 1
2026-03-07 16:01