导读:本期聚焦于张衡创作的《JavaScript懒加载怎么实现?图片与组件延迟加载完整攻略》,敬请观看详情。页面加载速度慢、首屏白屏时间长,往往是资源一次性加载惹的祸。懒加载的核心思路是只在资源进入可视区域时才真正加载,从而大幅减少初始请求量。本文将从图片懒加载入手,先讲解传统的滚动监听方案,再重点分析Intersection Observer这一现代API的原理与用法,包括loading属性的原生支持情况;随后延伸到组件级懒加载,介绍动态import配合React.lazy、Vue异步组件的实现方式;最后总结懒加载的适用场景、性能收益以及常见踩坑点,帮助你构建更流畅的Web应用。

懒加载(Lazy Loading)是一种按需加载资源的优化策略:只有当资源真正需要展示时才发起请求,而不是页面初始化时就加载全部内容。对于包含大量图片、长列表或复杂组件的页面来说,懒加载能显著减少首屏请求数量、降低带宽消耗、加快可交互时间。本文将围绕图片懒加载和组件懒加载两条主线,系统讲解实现思路与具体代码。

JavaScript懒加载怎么实现?图片与组件延迟加载完整攻略

一、图片懒加载:从滚动监听到Intersection Observer

图片懒加载的基本原理很简单:把真实的图片地址存放在data-src自定义属性中,src属性先不设置或使用占位图。当图片进入浏览器可视区域时,再把data-src的值赋给src,触发浏览器的下载行为。

最经典的实现方式是监听scroll事件,配合getBoundingClientRect计算图片相对于视口的位置:

// 获取所有需要懒加载的图片
const images = document.querySelectorAll('img[data-src]');

function lazyLoad() {
  const viewportHeight = window.innerHeight;
  images.forEach(img => {
    const rect = img.getBoundingClientRect();
    // 图片顶部进入视口时加载
    if (rect.top < viewportHeight && rect.bottom > 0) {
      img.src = img.dataset.src;
      img.removeAttribute('data-src');
    }
  });
}

window.addEventListener('scroll', throttle(lazyLoad, 200));
lazyLoad(); // 首次执行

这种方案的问题在于scroll事件触发频率极高,即使用了节流函数,频繁调用getBoundingClientRect仍会造成主线程压力,同时还会引发强制重排(reflow),在低端设备上表现明显卡顿。

更优雅的方案是使用Intersection Observer API。它是浏览器原生提供的交叉观察器,会在目标元素与视口的交叉状态发生变化时异步回调,完全避免了滚动监听带来的性能问题:

const observer = new IntersectionObserver((entries, obs) => {
  entries.forEach(entry => {
    if (entry.isIntersecting) {
      const img = entry.target;
      img.src = img.dataset.src;
      obs.unobserve(img); // 加载一次后停止观察
    }
  });
}, {
  root: null,        // 以视口为参照
  rootMargin: '0px 0px 200px 0px', // 提前200px预加载
  threshold: 0.1     // 交叉比例达到10%时触发
});

document.querySelectorAll('img[data-src]').forEach(img => {
  observer.observe(img);
});

其中rootMargin允许提前预加载即将进入视口的图片,避免用户快速滚动时看到空白;unobserve则确保每张图片只加载一次。此外,现代浏览器已支持原生的loading="lazy"属性,直接写在<img>标签上即可实现懒加载,无需任何JavaScript代码,但它的可定制性不如Intersection Observer,比如无法实现自定义占位动画和回调逻辑。

二、组件懒加载:动态import与框架级方案

图片之外,组件的延迟加载对打包体积优化同样关键。现代打包工具(如Webpack、Vite)支持动态import()语法,只有代码真正被执行时才会请求对应的chunk文件:

button.addEventListener('click', async () => {
  // 点击时才加载弹窗组件
  const { openDialog } = await import('./dialog.js');
  openDialog();
});

在React中,官方提供了React.lazy配合Suspense的组合方案。路由级别的懒加载是最常见的应用场景,用户访问哪个页面就加载哪个页面的代码:

import React, { Suspense, lazy } from 'react';

const Home = lazy(() => import('./pages/Home'));
const About = lazy(() => import('./pages/About'));

function App() {
  return (
    <Suspense fallback={<div>加载中...</div>}>
      <Routes>
        <Route path="/" element={<Home />} />
        <Route path="/about" element={<About />} />
      </Routes>
    </Suspense>
  );
}

Vue的实现思路类似,通过defineAsyncComponent(Vue 3)或直接在路由配置中书写函数形式的component即可:

import { createRouter, createWebHistory } from 'vue-router';

const routes = [
  {
    path: '/settings',
    component: () => import('./views/Settings.vue') // 路由懒加载
  }
];

const router = createRouter({
  history: createWebHistory(),
  routes
});

组件懒加载的价值在于把单个大bundle拆分成多个小chunk,配合浏览器并行下载能力和HTTP缓存,用户首次访问的下载量可以减少一半以上,后续访问还能命中缓存秒开。

三、常见踩坑点与最佳实践

懒加载虽好,但使用不当会带来体验问题。首先是首屏图片不应懒加载:首屏内容直接加载反而更快,如果对首屏图片也做延迟处理,用户会先看到占位符再看到图片,观感变差。其次是SEO问题,搜索引擎爬虫不一定执行JavaScript,依赖JS的懒加载可能导致图片不被收录,重要内容建议使用原生loading="lazy"或直接输出真实src

其次是占位符的处理。图片未加载时如果没有预留高度,加载完成后会引起布局抖动(CLS指标恶化)。推荐为图片明确设置宽高属性,或使用宽高比固定的容器、低清晰度模糊占位图(LQIP)来稳定布局:

<div style="aspect-ratio: 16 / 9; background: #eee;">
  <img data-src="real-image.jpg" width="640" height="360" alt="示例图" />
</div>

最后是失败兜底与用户体验:网络请求可能失败,应监听error事件提供重试机制或降级占位图;对于懒加载的组件,要设计合理的loading状态,避免用户在弱网下长时间面对空白区域。整体而言,懒加载的收益取决于页面规模——内容越多、交互路径越深的应用,延迟加载带来的性能提升越明显,建议通过Lighthouse和Performance面板持续监测优化效果。

懒加载Intersection Observer图片延迟加载修改时间:2026-09-01 04:14:46

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