JavaScript 图片懒加载的三种实现方案:基础、节流与 IntersectionObserver
本文详解 JavaScript 实现图片懒加载的三种方式。首先介绍通过 data-src 属性替换 src 的基础方法;其次针对 scroll 事件高频触发问题,引入函数节流(throttle)优化性能;最后讲解利用现代浏览器支持的 IntersectionObserver API 实现自动观察元素可见性的简洁方案,帮助提升长页面加载速度与用户体验。
图片懒加载原理与优势
延迟加载,亦称惰性加载,是指在长网页中推迟加载图像资源的策略。
只有当用户滚动页面,使图像进入浏览器视口范围时,这些图像才会开始加载。
这与图像预加载机制相反。在长网页应用中采用延迟加载策略,能够显著加快页面的初始加载速度。
在特定场景下,这种策略还有助于降低服务器端的负载压力。
延迟加载的主要优势包括:
显著提升用户体验。若页面图片数量庞大,一次性全部加载会导致页面卡顿。通过按需请求图片,不仅能有效减轻服务器带宽压力和流量消耗,也能降低浏览器的渲染负担。
基础实现方案
方法一:基础实现
实现思路是将页面上所有图片的 src 属性临时设置为一个占位图(如 loading.gif),而将真实的图片路径存储在 data-src 自定义属性中。
在页面滚动过程中,实时计算图片相对于视口的位置与当前滚动距离。一旦检测到图片进入浏览器可视区域,便将图片的 src 属性更新为 data-src 中存储的真实路径。
<img src="loading.png" data-src="image.png">
img { display: block; margin-bottom: 50px; }
function lazyload() {
var images = document.getElementsByTagName('img');
var n = 0; // 用于存储图片加载到的位置,避免每次都从第一张图片开始遍历
return function() {
var seeHeight = document.documentElement.clientHeight;
var scrollTop = document.documentElement.scrollTop || document.body.scrollTop;
for(var i = n; i < images.length; i++) {
if (images[i].offsetTop < seeHeight + scrollTop) {
if (images[i].getAttribute('src') === 'loading.png') {
images[i].src = images[i].getAttribute('data-src');
}
n = n + 1;
}
}
}
}
lazyload(); //初始化首页的页面图片
window.addEventListener('scroll', lazyload(), false);
基于函数节流的性能优化
方法二:性能优化
上述基础方法虽然逻辑简单,但存在性能隐患。由于 scroll 事件在滚动时会高频触发,频繁执行计算逻辑会严重影响浏览器性能。因此,需要对 lazyload 函数应用函数节流(throttle)或函数去抖(debounce)技术进行处理。
函数节流与去抖机制
此处 HTML 和 CSS 代码保持不变,经过 throttle 处理后的 JavaScript 代码如下:
function throttle (fn, delay, atleast) {
var timeout = null,
startTime = new Date();
return function () {
var curTime = new Date();
clearTimeout(timeout);
if (curTime - startTime >= atleast) {
fn ();
startTime = curTime;
} else {
timeout = setTimeout (fn, delay);
}
}
}
function lazyload() {
var images = document.getElementsByTagName('img'),
n = 0; //存储图片加载到的位置,避免每次都从第一张图片开始遍历
return function() {
var seeHeight = document.documentElement.clientHeight;
var scrollTop = document.documentElement.scrollTop || document.body.scrollTop;
for(var i = n; i < images.length; i++) {
if(images[i].offsetTop < seeHeight + scrollTop) {
if(images[i].getAttribute('src') === 'loading.png') {
images[i].src = images[i].getAttribute('data-src');
}
n = n + 1;
}
}
}
}
lazyload(); //初始化首页的页面图片
window.addEventListener('scroll', throttle(lazyload(), 500, 1000), false);
使用 IntersectionObserver API 的现代方案
方法三:使用 IntersectionObserver API
现代浏览器提供了新的 IntersectionObserver API,它能够自动“观察”元素是否进入可视区域。
该方法的代码实现非常简洁,但需注意许多旧版浏览器尚不支持此 API。

- IntersectionObserver 接收一个回调函数,当被观察的元素集合进入或离开视口时,该回调函数会被执行。
- 通过 io.observe 方法,需要逐个添加希望被观察的元素。
- IntersectionObserver 实例内部管理着一个元素数组。当元素进入或离开视口时,它会自动在数组中添加或移除该元素,并触发相应的回调函数执行。
function query(selector) {
return Array.from(document.querySelectorAll(selector));
}
var io = new IntersectionObserver(function(items) {
items.forEach(function(item) {
var target = item.target;
if(target.getAttribute('src') == 'loading.png') {
target.src = target.getAttribute('data-src');
}
})
});
query('img').forEach(function(item) {
io.observe(item);
以上即为本文介绍的全部内容,希望这些实现方式能对您的学习有所帮助,欢迎继续支持本站获取更多技术分享。
ES6模块化中js文件怎么用import和export交互
2026-11-05 17:00:48
JS读取本地文件时报错或无响应的常见原因
2026-11-05 16:32:31
let、const与var的区别:JavaScript变量声明最佳实践
2026-11-05 14:16:38
JS中直接定义静态二维数组的字面量写法
2026-11-05 14:16:08
JS 怎么查找字符串中所有匹配项的位置
2026-11-05 14:15:53
