导读:本期聚焦于小伙伴创作的《滚动翻页中图片懒加载失效的五大原因与解决方案》,敬请观看详情,探索知识的价值。以下视频、文章将为您系统阐述其核心内容与价值。如果您觉得《滚动翻页中图片懒加载失效的五大原因与解决方案》有用,将其分享出去将是对创作者最好的鼓励。

滚动翻页时JS懒加载图片失败原因及解决方案

在前端开发中,图片懒加载是优化页面性能、减少初始资源加载压力的常用手段。不少开发者在实现滚动翻页场景下的懒加载功能时,会遇到图片无法正常加载的问题,本文将从常见原因出发,结合实际代码示例逐一分析并提供对应解决方案。

一、基础懒加载实现原理回顾

常见的图片懒加载核心逻辑是:先将图片的真实地址存放在自定义属性(如data-src)中,初始时src属性为空或占位图,当页面滚动到图片进入可视区域时,再将data-src的值赋值给src,触发图片加载。基础实现示例代码如下:

// 基础懒加载实现
function lazyLoadImages() {
  // 获取所有需要懒加载的图片
  const lazyImages = document.querySelectorAll('img[data-src]');
  // 获取可视区域高度
  const windowHeight = window.innerHeight;
  // 获取当前滚动距离
  const scrollTop = window.pageYOffset || document.documentElement.scrollTop;

  lazyImages.forEach(img => {
    // 获取图片距离页面顶部的距离
    const imgTop = img.offsetTop;
    // 判断图片是否进入可视区域(预留100px提前加载空间)
    if (imgTop < windowHeight + scrollTop + 100) {
      // 将data-src的值赋给src,触发加载
      img.src = img.getAttribute('data-src');
      // 加载完成后移除data-src属性,避免重复处理
      img.removeAttribute('data-src');
    }
  });
}

// 监听滚动事件
window.addEventListener('scroll', lazyLoadImages);
// 初始加载时执行一次
lazyLoadImages();

二、滚动翻页场景下懒加载失败的常见原因

1. 滚动事件未正确绑定到翻页容器

很多滚动翻页场景并非基于window滚动,而是使用自定义容器(如div)设置overflow-y: auto实现内容滚动。如果仍然监听window的滚动事件,会导致无法正确获取容器的滚动状态和可视区域范围,懒加载判断失效。

错误示例:假设翻页容器是idscroll-containerdiv,错误监听如下:

// 错误:仍然监听window滚动,实际滚动的是#scroll-container
window.addEventListener('scroll', lazyLoadImages);

正确做法应该是监听翻页容器的滚动事件,同时计算可视区域时需要基于容器的属性:

// 获取翻页容器
const scrollContainer = document.getElementById('scroll-container');

function lazyLoadImagesInContainer() {
  // 容器可视区域高度
  const containerHeight = scrollContainer.clientHeight;
  // 容器滚动距离
  const containerScrollTop = scrollContainer.scrollTop;
  // 获取容器内所有待加载图片
  const lazyImages = scrollContainer.querySelectorAll('img[data-src]');

  lazyImages.forEach(img => {
    // 计算图片相对于容器顶部的距离
    const imgTop = img.offsetTop - scrollContainer.offsetTop;
    if (imgTop < containerHeight + containerScrollTop + 100) {
      img.src = img.getAttribute('data-src');
      img.removeAttribute('data-src');
    }
  });
}

// 监听容器滚动事件
scrollContainer.addEventListener('scroll', lazyLoadImagesInContainer);
// 初始执行一次
lazyLoadImagesInContainer();

2. 翻页新增内容未重新查询待加载图片

滚动翻页通常是动态加载新内容并插入到页面中,如果懒加载的逻辑只在初始时执行一次,或者每次滚动时只查询初始存在的img[data-src]元素,那么新插入的翻页内容中的待加载图片不会被纳入判断范围,自然无法触发加载。

错误示例:每次滚动都只查询初始存在的图片,不会处理新增内容:

// 初始查询一次,后续滚动不会重新获取新增的待加载图片
const lazyImages = document.querySelectorAll('img[data-src]');

function lazyLoadImages() {
  const windowHeight = window.innerHeight;
  const scrollTop = window.pageYOffset || document.documentElement.scrollTop;
  // 遍历的是初始查询的lazyImages,新增图片不在其中
  lazyImages.forEach(img => {
    const imgTop = img.offsetTop;
    if (imgTop < windowHeight + scrollTop + 100) {
      img.src = img.getAttribute('data-src');
      img.removeAttribute('data-src');
    }
  });
}

window.addEventListener('scroll', lazyLoadImages);

正确做法是在每次滚动触发懒加载时,重新查询当前页面中所有仍带有data-src属性的图片,确保新增内容被覆盖:

function lazyLoadImages() {
  const windowHeight = window.innerHeight;
  const scrollTop = window.pageYOffset || document.documentElement.scrollTop;
  // 每次执行时重新查询所有待加载图片
  const lazyImages = document.querySelectorAll('img[data-src]');

  lazyImages.forEach(img => {
    const imgTop = img.offsetTop;
    if (imgTop < windowHeight + scrollTop + 100) {
      img.src = img.getAttribute('data-src');
      img.removeAttribute('data-src');
    }
  });
}

window.addEventListener('scroll', lazyLoadImages);

3. 图片位置计算错误

懒加载的核心判断是图片是否进入可视区域,如果计算图片位置和可视区域范围的逻辑有误,就会导致判断失效。常见计算错误包括:

  • 使用offsetTop时,没有考虑父元素的偏移量,尤其是当图片位于嵌套布局中时,offsetTop是相对于最近定位父元素的距离,而非页面顶部。

  • 翻页容器的滚动距离和可视区域高度计算混用了window和容器的属性,比如用了容器的clientHeight却用了window.pageYOffset作为滚动距离。

  • 没有预留提前加载的缓冲空间,图片刚进入可视区域边缘才触发加载,用户可能已经滚动过去,显得加载失败。

建议使用getBoundingClientRect方法获取元素相对于可视区域的位置,该方法返回的属性不受父元素布局影响,计算更准确:

function lazyLoadImages() {
  const lazyImages = document.querySelectorAll('img[data-src]');
  lazyImages.forEach(img => {
    // 获取图片相对于可视区域的位置信息
    const rect = img.getBoundingClientRect();
    // rect.top是图片顶部到可视区域顶部的距离,rect.bottom是图片底部到可视区域顶部的距离
    // 当图片顶部小于可视区域高度(进入可视区域),且图片底部大于0(没有完全滚出可视区域)时触发加载
    if (rect.top < window.innerHeight && rect.bottom > 0) {
      img.src = img.getAttribute('data-src');
      img.removeAttribute('data-src');
    }
  });
}

window.addEventListener('scroll', lazyLoadImages);

4. 翻页请求未完成时滚动触发懒加载

滚动翻页的逻辑通常是:滚动到底部时触发接口请求,获取新一页的数据,然后将新内容插入页面。如果新内容插入是异步的,在插入完成前,懒加载逻辑已经执行,此时新内容的图片还不存在于DOM中,自然无法被处理。或者翻页请求失败时,没有新内容插入,但懒加载逻辑仍然执行,不会出现新的加载行为,被误认为加载失败。

解决方案是确保在翻页内容插入DOM后再执行一次懒加载逻辑,同时处理请求失败的情况:

// 翻页加载函数
async function loadNextPage() {
  // 避免重复请求
  if (window.isLoading) return;
  window.isLoading = true;
  try {
    // 模拟请求翻页数据,实际项目中替换为真实接口地址 https://www.ipipp.com/api/list
    const response = await fetch('https://www.ipipp.com/api/list?page=' + window.currentPage);
    const data = await response.json();
    if (data.list.length > 0) {
      // 将新内容插入容器
      const container = document.getElementById('content-container');
      data.list.forEach(item => {
        const img = document.createElement('img');
        img.setAttribute('data-src', item.imgUrl);
        img.alt = item.title;
        container.appendChild(img);
      });
      // 新内容插入后执行一次懒加载,处理新增图片
      lazyLoadImages();
      window.currentPage++;
    }
  } catch (error) {
    console.error('翻页请求失败:', error);
  } finally {
    window.isLoading = false;
  }
}

// 监听滚动到底部触发翻页
window.addEventListener('scroll', () => {
  const scrollTop = window.pageYOffset || document.documentElement.scrollTop;
  const windowHeight = window.innerHeight;
  const documentHeight = document.documentElement.scrollHeight;
  // 滚动到距离底部100px时触发翻页
  if (scrollTop + windowHeight >= documentHeight - 100) {
    loadNextPage();
  }
  // 同时执行懒加载
  lazyLoadImages();
});

5. 图片真实地址属性或赋值逻辑错误

部分场景中,开发者可能会用不同的自定义属性存储图片真实地址,比如data-originallazy-src等,如果懒加载逻辑中读取的属性名和实际存储的属性名不一致,就无法正确获取地址,导致src赋值失败。另外,如果赋值后没有移除自定义属性,会导致每次滚动都重复赋值,虽然不影响加载,但可能造成性能问题,不过如果判断逻辑有问题,也可能出现异常。

建议统一自定义属性名称,比如统一使用data-src,并在赋值后移除该属性,避免重复处理:

function lazyLoadImages() {
  const lazyImages = document.querySelectorAll('img[data-src]');
  lazyImages.forEach(img => {
    const rect = img.getBoundingClientRect();
    if (rect.top < window.innerHeight && rect.bottom > 0) {
      // 读取data-src属性
      const realSrc = img.getAttribute('data-src');
      if (realSrc) {
        img.src = realSrc;
        // 赋值完成后移除data-src,避免下次重复处理
        img.removeAttribute('data-src');
      }
    }
  });
}

三、其他注意事项

除了上述常见原因,还有一些细节可能导致懒加载失败:

  • 图片初始样式设置为display: none,此时getBoundingClientRect返回的topbottom等属性会异常,需要确保在图片进入可视区域前将其显示,或者调整判断逻辑。

  • 频繁的滚动事件触发会导致性能问题,建议使用节流函数优化滚动事件的处理,避免每次滚动都执行大量查询和计算:

// 节流函数,限制函数在一定时间内只执行一次
function throttle(fn, delay = 200) {
  let timer = null;
  return function(...args) {
    if (!timer) {
      timer = setTimeout(() => {
        fn.apply(this, args);
        timer = null;
      }, delay);
    }
  };
}

// 使用节流后的懒加载函数
window.addEventListener('scroll', throttle(lazyLoadImages, 200));

如果项目中使用了第三方懒加载库,还需要检查库的配置是否符合滚动翻页的场景,比如是否支持动态内容、是否正确配置了滚动容器等,必要时可以查看库的文档或源码排查问题。

懒加载 滚动翻页 性能优化 前端开发 JavaScript

免责声明:已尽一切努力确保本网站所含信息的准确性。网站部分内容来源于网络或由用户自行发表,内容观点不代表本站立场。本站是个人网站免费分享,内容仅供个人学习、研究或参考使用,如内容中引用了第三方作品,其版权归原作者所有。若内容触犯了您的权益,请联系我们进行处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。前端、网络、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握网站开发与运维所需的核心技术栈。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端逻辑,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。