为什么我的图片懒加载在滚动到底部时会重复加载?

子荧 Dev 阅读 47

我在做一个图片列表页用懒加载,用Intersection Observer监听,但滚动到页面最底部时,图片会重复触发加载两次。之前试过把阈值改成0.1和调整根边距都不行,控制台还报错说”Cannot read properties of undefined (reading ‘src’)”。

代码是这样的:observer.observe(document.querySelectorAll('.lazy-img')),然后回调里用entries.forEach(entry => { if (entry.isIntersecting) { ... }}。但发现当最后一个元素出现时,回调执行了两次,导致重复请求和错误。


const observer = new IntersectionObserver((entries) => {
  entries.forEach(entry => {
    if (entry.isIntersecting) {
      entry.target.src = entry.target.dataset.src;
      observer.unobserve(entry.target);
    }
  });
}, { rootMargin: '0px', threshold: 1.0 });

document.querySelectorAll('.lazy-img').forEach(img => observer.observe(img));
我来解答 赞 17 收藏
二维码
手机扫码查看
2 条解答
博主梦媛
问题出在两个地方:

一是 threshold 设为 1.0 太大了,需要元素完全进入视口才触发,这样在边界处很容易触发多次。

二是 entry.target 可能在某些情况下取不到,应该加个保险。

改一下:

const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting && entry.target) {
const img = entry.target;
const src = img.dataset.src;

if (src) {
img.src = src;
img.classList.remove('lazy-img');
observer.unobserve(img);
}
}
});
}, { rootMargin: '100px', threshold: 0 });

document.querySelectorAll('.lazy-img').forEach(img => observer.observe(img));


改动点:

rootMargin 改成 '100px',让图片在距离视口100px时就开始加载,这样用户还没看到就加载完了,体验更好。

threshold 改成 0,只要元素一出现就触发,别等完全进入。

加了 entry.targetsrc 的判断,防止报错。

加载完记得调用 unobserve 取消监听,这样就不会重复触发了。

另外建议给 img 标签加个初始的 src 用占位图或者空字符串,避免加载时出现破图。
点赞
2026-03-13 10:02
♫瑞丽
♫瑞丽 Lv1
Intersection Observer回调触发多次是常见问题,你的判断条件不够严谨导致重复执行。加个 !entry.target.src 判断再执行加载,重复触发问题就解决了。

const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting && !entry.target.src) {
entry.target.src = entry.target.dataset.src;
observer.unobserve(entry.target);
}
});
}, { rootMargin: '0px', threshold: 1.0 });

document.querySelectorAll('.lazy-img').forEach(img => observer.observe(img));
点赞 17
2026-02-04 15:18