js怎么实现图片懒加载

js怎么实现图片懒加载
最新回答
寡走渡人

2026-06-02 00:51:20

在JavaScript中实现图片懒加载的核心是延迟加载非视口内的图片,通过以下方案可兼顾性能、兼容性与用户体验:

一、推荐方案:IntersectionObserver API

原理:通过监听元素与视口的交叉状态,在图片即将进入视口时加载真实资源。实现步骤:

  1. HTML结构调整将图片真实地址存储在data-src属性中,初始src可设为占位图或留空:

    <img alt="描述文字" class="lazyload-img" data-src="真实图片地址.jpg">
  2. JavaScript逻辑

    document.addEventListener('DOMContentLoaded', () => { const lazyImages = document.querySelectorAll('.lazyload-img'); if ('IntersectionObserver' in window) { const observer = new IntersectionObserver((entries) => { entries.forEach(entry => { if (entry.isIntersecting) { const img = entry.target; img.src = img.dataset.src; // 赋值真实地址 img.removeAttribute('data-src'); // 移除冗余属性 observer.unobserve(img); // 停止观察已加载图片 } }); }, { rootMargin: '0px 0px 100px 0px', // 提前100px加载 threshold: 0.01 // 1%可见即触发 }); lazyImages.forEach(img => observer.observe(img)); } else { // 回退方案:监听scroll事件(见下文) }});

优势:

  • 性能高效,避免频繁DOM计算。
  • 支持rootMargin提前加载,防止内容“蹦出”。
  • 代码简洁,可维护性强。
二、回退方案:Scroll事件监听

适用场景:需兼容不支持IntersectionObserver的旧浏览器(如IE)。实现逻辑:

  1. 节流处理:减少滚动事件触发频率。
  2. 位置判断:通过getBoundingClientRect()检查元素是否进入视口。
let isLoading = false;const lazyLoad = () => { if (isLoading) return; isLoading = true; setTimeout(() => { lazyImages.forEach(img => { const rect = img.getBoundingClientRect(); if (rect.top <= window.innerHeight && rect.bottom >= 0) { img.src = img.dataset.src; img.removeAttribute('data-src'); } }); isLoading = false; }, 200); // 节流延迟};window.addEventListener('scroll', lazyLoad);window.addEventListener('resize', lazyLoad);lazyLoad(); // 初始检查

缺点:

  • 频繁计算可能导致性能问题,需配合节流/防抖优化。
  • 代码复杂度高于IntersectionObserver。
三、关键细节优化
  1. 占位符设计

    使用低分辨率图、模糊图(CSS滤镜)或纯色背景避免布局偏移:.lazyload-img { background: #f0f0f0; /* 纯色占位 */}

    或通过<img src="低质量占位图.jpg" data-src="高清图.jpg">实现平滑过渡。

  2. 错误处理监听onerror事件替换失败图片或隐藏元素:

    img.onerror = () => { img.src = '默认错误图.jpg'; // 或 img.style.display = 'none';};
  3. 背景图片懒加载动态修改background-image样式:

    const observer = new IntersectionObserver((entries) => { entries.forEach(entry => { if (entry.isIntersecting) { const div = entry.target; div.style.backgroundImage = `url(${div.dataset.bg})`; observer.unobserve(div); } });});document.querySelectorAll('.lazy-bg').forEach(div => { div.style.backgroundImage = 'url(占位图.jpg)'; // 初始占位 observer.observe(div);});
四、原生方案:loading="lazy"属性

适用场景:简单需求且无需精细控制时,优先使用原生属性:

<img src="占位图.jpg" data-src="真实图.jpg" loading="lazy" alt="描述">

优势:

  • 无需JavaScript,性能更优。
  • 浏览器自动处理加载时机。

局限:

  • 无法自定义rootMargin或处理背景图。
  • 兼容性需考虑(IE不支持)。
五、性能与用户体验价值
  1. 减少首屏资源加载量:优化FCP(首次内容绘制)和LCP(最大内容绘制)指标。
  2. 降低服务器压力:减少不必要的图片请求,节省带宽。
  3. 提升SEO:符合Google Core Web Vitals标准,提高搜索排名。
总结方案选择
  • 现代浏览器:优先使用IntersectionObserver + loading="lazy"。
  • 旧浏览器兼容:回退至Scroll事件监听(需节流)。
  • 背景图片:通过JavaScript动态修改样式。
  • 极简需求:直接使用loading="lazy"属性。

通过合理选择方案,可显著提升页面加载速度和用户体验,同时降低维护成本。