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

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

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

过去,实现懒加载通常需要监听 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 不仅代码量极少,而且在性能上远超传统方法,因为它将复杂的计算交给了浏览器底层去高效处理,不会阻塞主线程。

相关推荐

轻松玩转windows控制台(五):彻底搞懂屏幕缓冲区

写在前面在上一篇文章中,详细地介绍了控制台程序最容易令人困惑和混淆的地方,即什么是控制台窗口,什么是控制台屏幕缓冲区。并通过几个示例程序,演示了如何设置控制台窗口“显示区域”的大小。(轻松玩转wind...

零基础教你学前端——85、高度自适应

这节课,我们学习如何让元素的宽度和高度在容器里自适应。什么是宽高自适应呢?页面里有两个div,开始的时候宽度都是800px,当我们将浏览器窗口的宽度拖动到小于800px的时候,我们发现:上面的...

Grafana可视化平台面板之Gauge仪表和Bar Gauge条形仪表

仪表(Gauge)仪表是一种用于展示单个数值指标并跟踪其随时间变化的图表类型。它通常用于显示系统的实时状态或关键性能指标,如CPU使用率、内存占用率等。仪表通过一个圆形或半圆形的表盘来展示数值,并可以...

网页五指棋游戏(五指棋单机)

完整代码如下,大家可以保存到html文件点击打开,就可以看到如上效果<!DOCTYPEhtml><htmllang="zh-CN"><head>...

2020年度中央机关公开遴选和公开选调公务员报名即将开始

新华社北京10月27日电(记者林晖)记者27日从国家公务员局获悉,2020年度中央机关公开遴选和公开选调公务员报名即将开始,考生可于10月28日8时至11月6日18时期间,登录“2020年度中央机关公...

小程序学习日志7:可滚动的视图区域组件(滚动条)

导读经过这段日子的学习,大家对小程序的了解多了多少呢?我们这段时间学了很多组件的用法,以及这些组件的属性和属性的合法值,图片、文字、块,还了解了不少的样式代码和小程序的基本知识。我们今天来讲一个可滚动...

四叶草SEO:主要SEO作弊方法之隐藏文字

石家庄四叶草SEO小编在这里介绍黑帽,并不意味鼓励大家使用黑帽,恰恰相反,而是因为很多SEOer无意之中就使用了黑帽手法,自己却不知道。对于一个正常的商业网站和大部分个人网站来说,做好内容,正常优化,...

鸿蒙仓颉语言开发实战教程:商城搜索页

大家好,今天要分享的是仓颉语言商城应用的搜索页。搜索页的内容比较多,都有点密集恐惧症了,不过我们可以从上至下将它拆分开来,逐一击破。导航栏搜索页的的最顶部是导航栏,由返回按钮和搜索框两部分组成,比较简...

鸿蒙Next仓颉语言开发实战教程:设置页面

仓颉语言商城应用的页面开发教程接近尾声了,今天要分享的是设置页面:导航栏还是老样式,介绍过很多次了,今天不再赘述。这个页面的内容主要还是介绍List容器的使用。可以看出列表内容分为三组,所以我们要用到...

CSS box-sizing 属性详解(css中box属性有哪些)

box-sizing是CSS的一个非常重要的属性。CSS的box-sizing属性用于控制元素尺寸的计算方式,决定了元素的宽度(width)和高度(height)是否包含内边距(...

68.C# MenuStrip控件(c#基本控件)

摘要MenuStrip控件是在.NETFramework版本2.0中引入的。可以通过MenuStrip控件,轻松创建像MicrosoftOffice中的菜单。MenuStrip...

Qt使用布局管理器实现扩展对话框(qt选择文件路径对话框)

今天跟大家讲讲扩展对话框的实现;扩展对话框效果如下所示:(1)初始界面:(2)单击<More>按钮:(3)再次单击<More>按钮:这节主要讲解用布局管理器方式实现,下节讲解用...

探讨小程序开发的布局(小程序开发部署流程)

谈到小程序布局就不得不谈WXSS(WeiXinStyleSheets)!WXSS是微信小程序专用的样式语言。WXSS与css虽然在尺寸单位和样式导入不同,但是,具有CSS大部分特性。小程序的样式...

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

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

JS实现轮播图案例(一看就懂,逻辑清晰)

1.功能分析实现如图所示的轮播图,要实现的功能主要有:鼠标经过轮播图模块,左右按钮显示,离开隐藏左右按钮。点击右侧按钮一次,图片下滑一张;点击左侧按钮,图片上滑一张。图片播放的同时,下面小圆圈模块跟...