百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术文章 > 正文

图片懒加载的现代 JavaScript 实现,仅需 10 行代码

zhezhongyun 2025-07-03 02:15 38 浏览

过去,实现懒加载通常需要监听 scroll 事件,并结合 getBoundingClientRect() 等方法计算元素位置,代码不仅繁琐,而且频繁的计算会引发性能问题。

现代浏览器提供了 Intersection Observer API,让我们得以用一种极其高效和简洁的方式来实现懒加载。多简洁?核心逻辑只需 10 行代码。

第一步:HTML 结构准备

懒加载的原理很简单:我们不直接将图片的 URL 放在 src 属性里,而是先放在一个自定义的 data-* 属性(如 data-src)中。src 属性可以指向一个极小的占位符图片(比如一个 1x1 像素的透明 GIF 或低质量的模糊图),以避免出现 broken image 图标。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>现代图片懒加载</title>
    <style>
        /* 给图片一个最小高度,以便在加载前占据空间 */
        img {
            display: block;
            margin-bottom: 50px;
            min-height: 200px;
            background-color: #f0f0f0; /* 简单的占位背景色 */
        }
    </style>
</head>
<body>
    <h1>向下滚动查看图片懒加载效果</h1>

    <!-- 使用 class="lazy" 来标识需要懒加载的图片 -->
    <!-- src 指向一个占位符,data-src 存放真实图片地址 -->
    <img class="lazy" src="placeholder.gif" data-src="https://source.example.com/random/800x600?nature" alt="Lazy Loaded Image 1">
    <img class="lazy" src="placeholder.gif" data-src="https://source.example.com/random/800x600?city" alt="Lazy Loaded Image 2">
    <img class="lazy" src="placeholder.gif" data-src="https://source.example.com/random/800x600?people" alt="Lazy Loaded Image 3">
    <img class="lazy" src="placeholder.gif" data-src="https://source.example.com/random/800x600?tech" alt="Lazy Loaded Image 4">
    <img class="lazy" src="placeholder.gif" data-src="https://source.example.com/random/800x600?space" alt="Lazy Loaded Image 5">

    <script src="lazy-load.js"></script>
</body>
</html>

第二步:JavaScript 魔法(10 行代码实现)

现在,让我们见证奇迹。创建一个 lazy-load.js 文件,并写入以下代码:

// 1. 获取所有需要懒加载的图片
const lazyImages = document.querySelectorAll('.lazy');

// 2. 创建一个 IntersectionObserver 实例
const observer = new IntersectionObserver((entries, observer) => {
    // 3. 遍历所有被观察的元素
    entries.forEach(entry => {
        // 4. 如果元素进入视口
        if (entry.isIntersecting) {
            const img = entry.target;
            // 5. 将 data-src 的值赋给 src
            img.src = img.dataset.src;
            // 6. 移除 'lazy' 类,可选,但便于管理
            img.classList.remove('lazy');
            // 7. 停止观察该图片,释放资源
            observer.unobserve(img);
        }
    });
});

// 8. 让 observer 开始观察所有懒加载图片
lazyImages.forEach(image => {
    observer.observe(image);
});

就是这样!没有复杂的计算,没有混乱的事件监听器。代码清晰、高效,并且符合现代 Web 标准。

代码解析:为什么它能工作?

Intersection Observer (交叉观察器) 是一个浏览器 API,它允许我们异步地观察目标元素与其祖先元素或顶级文档视窗(viewport)的交叉状态。通俗地说,它能高效地告诉我们:“这个元素现在进入/离开屏幕了!”

让我们分解一下这 10 行代码:

  1. document.querySelectorAll('.lazy'): 我们选中所有带有 .lazy 类的图片元素。
  2. new IntersectionObserver(callback): 我们创建了一个观察器。它的构造函数接收一个回调函数,当目标元素的可见性发生变化时,这个回调函数就会被触发。
  3. entries: 这是回调函数接收的参数,是一个数组,包含了所有发生可见性变化的被观察元素的信息。
  4. entry.isIntersecting: 这是一个布尔值,true 代表目标元素至少有一部分进入了视口,false 则代表它完全离开了视口。这是我们实现懒加载的关键判断。
  5. img.src = img.dataset.src: 一旦图片可见,我们就执行核心操作:将存储在 data-src 中的真实图片 URL 赋值给 src 属性。浏览器会自动开始下载并显示图片。
  6. observer.unobserve(img): 这是至关重要的一步优化。一旦图片被加载,我们就不再需要观察它了。调用 unobserve 可以告诉观察器停止对该元素的监视,从而节省了宝贵的计算资源。
  7. observer.observe(image): 最后,我们启动观察器,让它开始监视每一个需要懒加载的图片。

进阶优化:预加载

Intersection Observer 还允许我们传入一个配置对象,来更精细地控制“交叉”的定义。其中 rootMargin 属性非常有用。

rootMargin 可以在视口(root)的每一边添加一个“外边距”,提前或延迟触发回调。例如,我们可以让图片在距离进入视口还有 200px 时就开始加载。

const options = {
    root: null, // 使用浏览器视口作为根
    rootMargin: '0px 0px 200px 0px', // 在底部增加 200px 的外边距
    threshold: 0 // 只要有 1 像素交叉就触发
};

const observer = new IntersectionObserver(callback, options);

这样设置后,用户向下滚动时,图片会“提前”加载,当图片真正进入视口时已经准备好了,体验会更加流畅。

Intersection Observer 不仅代码量极少,而且在性能上远超传统方法,因为它将复杂的计算交给了浏览器底层去高效处理,不会阻塞主线程。

相关推荐

Python入门学习记录之一:变量_python怎么用变量

写这个,主要是对自己学习python知识的一个总结,也是加深自己的印象。变量(英文:variable),也叫标识符。在python中,变量的命名规则有以下三点:>变量名只能包含字母、数字和下划线...

python变量命名规则——来自小白的总结

python是一个动态编译类编程语言,所以程序在运行前不需要如C语言的先行编译动作,因此也只有在程序运行过程中才能发现程序的问题。基于此,python的变量就有一定的命名规范。python作为当前热门...

Python入门学习教程:第 2 章 变量与数据类型

2.1什么是变量?在编程中,变量就像一个存放数据的容器,它可以存储各种信息,并且这些信息可以被读取和修改。想象一下,变量就如同我们生活中的盒子,你可以把东西放进去,也可以随时拿出来看看,甚至可以换成...

绘制学术论文中的“三线表”具体指导

在科研过程中,大家用到最多的可能就是“三线表”。“三线表”,一般主要由三条横线构成,当然在变量名栏里也可以拆分单元格,出现更多的线。更重要的是,“三线表”也是一种数据记录规范,以“三线表”形式记录的数...

Python基础语法知识--变量和数据类型

学习Python中的变量和数据类型至关重要,因为它们构成了Python编程的基石。以下是帮助您了解Python中的变量和数据类型的分步指南:1.变量:变量在Python中用于存储数据值。它们充...

一文搞懂 Python 中的所有标点符号

反引号`无任何作用。传说Python3中它被移除是因为和单引号字符'太相似。波浪号~(按位取反符号)~被称为取反或补码运算符。它放在我们想要取反的对象前面。如果放在一个整数n...

Python变量类型和运算符_python中变量的含义

别再被小名词坑哭了:Python新手常犯的那些隐蔽错误,我用同事的真实bug拆给你看我记得有一次和同事张姐一起追查一个看似随机崩溃的脚本,最后发现罪魁祸首竟然是她把变量命名成了list。说实话...

从零开始:深入剖析 Spring Boot3 中配置文件的加载顺序

在当今的互联网软件开发领域,SpringBoot无疑是最为热门和广泛应用的框架之一。它以其强大的功能、便捷的开发体验,极大地提升了开发效率,成为众多开发者构建Web应用程序的首选。而在Spr...

Python中下划线 ‘_’ 的用法,你知道几种

Python中下划线()是一个有特殊含义和用途的符号,它可以用来表示以下几种情况:1在解释器中,下划线(_)表示上一个表达式的值,可以用来进行快速计算或测试。例如:>>>2+...

解锁Shell编程:变量_shell $变量

引言:开启Shell编程大门Shell作为用户与Linux内核之间的桥梁,为我们提供了强大的命令行交互方式。它不仅能执行简单的文件操作、进程管理,还能通过编写脚本实现复杂的自动化任务。无论是...

一文学会Python的变量命名规则!_python的变量命名有哪些要求

目录1.变量的命名原则3.内置函数尽量不要做变量4.删除变量和垃圾回收机制5.结语1.变量的命名原则①由英文字母、_(下划线)、或中文开头②变量名称只能由英文字母、数字、下画线或中文字所组成。③英文字...

更可靠的Rust-语法篇-区分语句/表达式,略览if/loop/while/for

src/main.rs://函数定义fnadd(a:i32,b:i32)->i32{a+b//末尾表达式}fnmain(){leta:i3...

C++第五课:变量的命名规则_c++中变量的命名规则

变量的命名不是想怎么起就怎么起的,而是有一套固定的规则的。具体规则:1.名字要合法:变量名必须是由字母、数字或下划线组成。例如:a,a1,a_1。2.开头不能是数字。例如:可以a1,但不能起1a。3....

Rust编程-核心篇-不安全编程_rust安全性

Unsafe的必要性Rust的所有权系统和类型系统为我们提供了强大的安全保障,但在某些情况下,我们需要突破这些限制来:与C代码交互实现底层系统编程优化性能关键代码实现某些编译器无法验证的安全操作Rus...

探秘 Python 内存管理:背后的神奇机制

在编程的世界里,内存管理就如同幕后的精密操控者,确保程序的高效运行。Python作为一种广泛使用的编程语言,其内存管理机制既巧妙又复杂,为开发者们提供了便利的同时,也展现了强大的底层控制能力。一、P...