JavaScript懒加载是一种常见的前端性能优化手段,核心思路是延迟加载非首屏可见的图片和组件,只有当这些资源进入浏览器的可视区域时,才触发实际的加载逻辑,从而减少初始页面的资源请求数量,加快首屏渲染速度。

懒加载的实现原理
懒加载的核心依赖两个关键判断:一是判断元素是否已经进入可视区域,二是判断元素是否还未被加载过。浏览器提供了IntersectionObserver接口,可以高效监听元素与可视区域的交叉状态,不需要手动计算元素的位置和滚动距离,性能比传统的滚动事件监听更好。
对于不支持IntersectionObserver的旧浏览器,也可以通过监听scroll事件,结合getBoundingClientRect方法计算元素的位置,判断是否在可视区域内,不过这种方式需要注意防抖处理,避免滚动时频繁触发计算逻辑。
图片懒加载的实现
图片懒加载是最常见的应用场景,通常我们会给需要懒加载的图片设置一个自定义属性存储真实的图片地址,初始时src属性为空或者放一张占位图,当图片进入可视区域时,把自定义属性的值赋值给src属性,触发图片加载。
基于IntersectionObserver的实现
首先准备HTML结构,给懒加载的图片添加data-src属性存储真实地址:
<div class="img-container"> <img class="lazy-img" data-src="https://ipipp.com/img1.jpg" alt="示例图片1"> </div> <div class="img-container"> <img class="lazy-img" data-src="https://ipipp.com/img2.jpg" alt="示例图片2"> </div> <div class="img-container"> <img class="lazy-img" data-src="https://ipipp.com/img3.jpg" alt="示例图片3"> </div>
接下来编写JavaScript逻辑:
// 获取所有需要懒加载的图片元素
const lazyImgs = document.querySelectorAll('.lazy-img');
// 创建IntersectionObserver实例
const imgObserver = new IntersectionObserver((entries) => {
entries.forEach(entry => {
// 判断元素是否进入可视区域
if (entry.isIntersecting) {
const img = entry.target;
// 获取真实图片地址
const realSrc = img.dataset.src;
if (realSrc) {
// 赋值给src触发加载
img.src = realSrc;
// 加载完成后移除data-src属性,避免重复处理
img.removeAttribute('data-src');
}
// 停止监听当前元素
imgObserver.unobserve(img);
}
});
}, {
// 提前100px触发加载,提升用户体验
rootMargin: '100px'
});
// 遍历所有懒加载图片,开始监听
lazyImgs.forEach(img => {
imgObserver.observe(img);
});
传统scroll事件实现方式
如果需要兼容不支持IntersectionObserver的环境,可以使用以下实现:
// 获取所有懒加载图片
const lazyImgs = document.querySelectorAll('.lazy-img');
// 防抖函数,避免滚动时频繁执行
function debounce(fn, delay) {
let timer = null;
return function() {
if (timer) clearTimeout(timer);
timer = setTimeout(() => {
fn.apply(this, arguments);
}, delay);
};
}
// 判断元素是否在可视区域
function isInViewport(el) {
const rect = el.getBoundingClientRect();
return rect.top < window.innerHeight && rect.bottom > 0;
}
// 加载图片的逻辑
function loadLazyImgs() {
lazyImgs.forEach(img => {
// 已经加载过的图片跳过
if (img.dataset.loaded) return;
if (isInViewport(img)) {
const realSrc = img.dataset.src;
if (realSrc) {
img.src = realSrc;
img.dataset.loaded = true;
}
}
});
}
// 初始执行一次
loadLazyImgs();
// 监听滚动事件,使用防抖处理
window.addEventListener('scroll', debounce(loadLazyImgs, 200));
组件懒加载的实现
组件懒加载通常用于单页应用中,比如Vue、React等框架的路由组件,或者页面中体积较大、非首屏需要的组件。这里以原生JavaScript实现动态加载组件为例,思路是当组件容器进入可视区域时,动态创建script标签加载组件的JS文件,或者动态渲染组件的HTML内容。
首先准备组件容器:
<div class="component-container" data-component="large-component"> <!-- 组件加载前的占位内容 --> <p>组件加载中...</p> </div>
对应的JavaScript实现逻辑:
// 获取所有需要懒加载的组件容器
const lazyComponents = document.querySelectorAll('.component-container');
// 创建IntersectionObserver实例监听组件容器
const componentObserver = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
const container = entry.target;
const componentName = container.dataset.component;
if (componentName && !container.dataset.loaded) {
// 动态加载组件的逻辑,这里以加载JS文件为例
const script = document.createElement('script');
script.src = `https://ipipp.com/components/${componentName}.js`;
script.onload = () => {
// 假设组件JS加载完成后会暴露一个init方法
if (window[componentName] && typeof window[componentName].init === 'function') {
window[componentName].init(container);
}
container.dataset.loaded = true;
};
document.body.appendChild(script);
}
// 停止监听当前容器
componentObserver.unobserve(container);
}
});
}, {
rootMargin: '200px'
});
// 开始监听所有组件容器
lazyComponents.forEach(container => {
componentObserver.observe(container);
});
如果是使用框架开发,比如Vue3,可以直接使用内置的defineAsyncComponent实现组件懒加载,React则可以使用React.lazy和Suspense组合实现,核心逻辑和原生实现一致,都是延迟加载组件的代码,在需要的时候再请求资源。
懒加载的注意事项
- 给懒加载的元素设置合适的宽高,避免加载完成后页面布局偏移,影响用户体验。
- 合理设置
rootMargin参数,提前触发加载,避免用户滚动到元素位置时才开始加载,出现空白等待的情况。 - 加载完成后及时停止监听元素,减少不必要的性能消耗。
- 对于关键的首屏图片和组件,不要使用懒加载,避免影响首屏渲染速度。
JavaScript懒加载图片延迟加载组件延迟加载修改时间:2026-07-06 05:27:28