0

0

js 怎么实现图片懒加载

煙雲

煙雲

发布时间:2025-08-25 13:33:01

|

892人浏览过

|

来源于php中文网

原创

图片懒加载的核心是延迟加载非首屏图片,等到接近用户视野时再加载,能显著提升页面加载速度、节省流量、优化用户体验;2. 推荐使用 intersectionobserver api 实现,通过将真实图片地址存于 data-src,用 src 显示占位符,当元素进入视口时再赋值真实地址并停止观察,同时提供不支持时的降级方案;3. 懒加载对性能至关重要,能减少首屏请求量,提升 fcp 和 lcp 指标,减轻主线程压力,改善 fid,节省移动端流量,并间接提升 seo 排名;4. intersectionobserver 相比传统 scroll 事件监听优势明显,它异步非阻塞,由浏览器底层优化交叉检测,避免频繁 reflow 和 repaint,性能更高且 api 更简洁;5. 实现时需注意避免布局抖动(设置 width、height 或 aspect-ratio)、防止空白闪烁(使用 lqip 占位符)、避免首屏图片被懒加载、确保无 js 时的降级显示,并可结合 rootmargin 预加载、使用 native loading="lazy" 属性、配合 srcset 响应式加载及渐进式图片格式进一步优化体验。

js 怎么实现图片懒加载

图片懒加载,简单来说,就是让网页上的图片不是一股脑儿全加载出来,而是等到它们快要进入用户视野的时候,才真正去请求和渲染。这能显著提升页面初始加载速度,节省用户流量,让网站体验更流畅。

解决方案

实现图片懒加载,现代浏览器最推荐的方式是使用

IntersectionObserver
API。它提供了一种异步观察目标元素与祖先元素或顶级文档视窗交叉状态的方法,效率极高,避免了传统滚动事件监听带来的性能开销。

基本步骤是这样的:

  1. HTML 结构调整: 不要直接在

    @@##@@
    标签的
    src
    属性中放置图片真实地址。取而代之,使用一个自定义的
    data-src
    属性来存储真实地址,而
    src
    可以放一个占位符,比如一个纯透明的 1x1 像素 GIF 或一个低质量的模糊版本。

    @@##@@
  2. JavaScript 逻辑: 创建一个

    IntersectionObserver
    实例,它会监听所有带有
    lazyload
    类(或者你定义的任何类)的图片。当图片进入视口时,我们将
    data-src
    的值赋给
    src
    ,然后停止观察该图片。

    document.addEventListener('DOMContentLoaded', () => {
        const lazyImages = document.querySelectorAll('img.lazyload');
    
        const observer = new IntersectionObserver((entries, observer) => {
            entries.forEach(entry => {
                if (entry.isIntersecting) {
                    const img = entry.target;
                    img.src = img.dataset.src;
                    img.onload = () => {
                        // 图片加载完成后,可以移除占位符类或添加加载完成的类
                        img.classList.remove('lazyload');
                        // 考虑移除 data-src 属性,避免不必要的 DOM 属性
                        // delete img.dataset.src;
                    };
                    observer.unobserve(img); // 停止观察已加载的图片
                }
            });
        }, {
            // root: null, // 默认是视口
            rootMargin: '0px 0px 100px 0px', // 在图片进入视口前100px就开始加载
            threshold: 0 // 只要有一个像素进入视口就触发
        });
    
        lazyImages.forEach(img => {
            observer.observe(img);
        });
    
        // 考虑兼容性:如果浏览器不支持 IntersectionObserver,可以提供一个降级方案
        if (!('IntersectionObserver' in window)) {
            // 简单的降级方案:直接加载所有图片(可能导致性能问题,但至少能显示)
            lazyImages.forEach(img => {
                img.src = img.dataset.src;
                img.classList.remove('lazyload');
            });
            // 或者使用更复杂的基于 scroll 和 getBoundingClientRect 的方案
            // 但那会复杂得多,并且性能不如 IntersectionObserver
        }
    });

这个方案既考虑了性能,也兼顾了现代 Web 开发的最佳实践。

为什么图片懒加载对网站性能至关重要?

这问题问得好,因为懒加载绝不仅仅是“锦上添花”那么简单,它对网站的实际性能表现有着决定性的影响。从用户体验到搜索引擎排名,无处不在。

首先,最直观的,它能显著减少页面首次加载时的网络请求量和数据传输大小。想想看,一个包含几十张甚至上百张图片的页面,如果一股脑儿全加载,那得多大的带宽消耗?用户可能还在看页面顶部的内容,下面的图片却在悄悄消耗着流量和计算资源。懒加载就像一个聪明的管家,只在必要时才去取东西。这直接影响到首次内容绘制 (FCP)最大内容绘制 (LCP) 这些核心的性能指标,因为浏览器可以更快地渲染可见区域,而不是被大量图片请求阻塞。

其次,它能提升页面的响应速度和交互性。当浏览器忙于下载和解码大量图片时,JavaScript 的执行可能会被延迟,导致页面卡顿,用户点击按钮或滚动时感觉不流畅。懒加载减轻了主线程的压力,让页面在初期就能更快地响应用户操作,改善了首次输入延迟 (FID)

再者,对于移动设备用户,这简直是福音。移动网络环境复杂多变,流量也可能有限。懒加载不仅节省了流量,也让页面在信号不佳时能更快地呈现出主要内容,而不是一直转圈圈。我个人在用手机浏览一些图片特别多的网站时,如果没做懒加载,体验真的糟糕透了,加载慢不说,流量哗哗地跑。

最后,别忘了搜索引擎优化 (SEO)。虽然现代搜索引擎爬虫(特别是 Google)已经具备了执行 JavaScript 的能力,能“看到”懒加载后的图片。但一个快速加载的网站,本身就是搜索引擎青睐的对象。更快的加载速度意味着更好的用户体验,这间接有助于提升网站的排名。而且,如果你的网站因为图片过多导致加载过慢,搜索引擎可能会认为用户体验不佳,从而影响你的评分。所以,这不仅仅是技术实现,更是用户体验和业务目标的双重考量。

IntersectionObserver
相比传统方法的优势在哪里?

IntersectionObserver
出现之前,实现图片懒加载通常依赖于监听
scroll
事件,然后结合
getBoundingClientRect()
方法来判断元素是否进入了视口。这套老办法虽然能用,但问题可不少,简直是性能杀手。

多个微信小程序源码合集
多个微信小程序源码合集

微信小程序是一种轻量级的应用开发平台,由腾讯公司推出,主要应用于移动端,旨在提供便捷的用户体验,无需下载安装即可在微信内使用。本压缩包包含了丰富的源码资源,涵盖了多个领域的应用场景,下面将逐一介绍其中涉及的知识点。1. 图片展示:这部分源码可能涉及了微信小程序中的``组件的使用,用于显示图片,以及`wx.getSystemInfo`接口获取屏幕尺寸,实现图片的适配和响应式布局。可能还包括了图片懒加

下载

最大的痛点在于性能开销。每次用户滚动页面,

scroll
事件都会频繁触发,而每次触发,你都需要计算所有懒加载图片的
getBoundingClientRect()
。这个方法会强制浏览器进行回流 (reflow)重绘 (repaint),因为它需要获取最新的布局信息。想象一下,一个页面里有几十上百张图片,每次滚动都触发上百次计算和布局更新,那页面不卡才怪。这就像你开着一辆老旧的卡车,每隔几秒钟就得停下来检查一遍所有轮胎的气压,然后才能继续开。效率极低,而且用户体验会非常糟糕,页面会显得“抖动”或“卡顿”。

IntersectionObserver
则完全不同。它是一种异步的、非阻塞的 API。你告诉它你要观察哪些元素,以及它们与哪个根元素(通常是视口)的交叉情况。然后,浏览器会在内部进行优化,当被观察的元素与根元素发生交叉时(比如进入或离开视口),才会通知你。这个过程是在主线程之外进行的,不会阻塞页面的渲染和 JavaScript 的执行。它就像你雇了一个高效的巡逻员,他会默默地观察,只有当他发现目标进入了特定区域时,才来告诉你一声,你再根据这个通知去处理,而不是你每隔一秒就问他“目标进来了吗?”。

此外,

IntersectionObserver
的 API 设计也更简洁明了,使用起来比手动计算滚动位置和元素位置要方便得多。你不需要处理各种复杂的滚动边界条件,也不用担心节流(throttle)或防抖(debounce)的实现问题,因为它内部已经帮你做好了这些优化。

所以,从根本上讲,

IntersectionObserver
提供了更高效、更优雅、更符合现代 Web 性能要求的解决方案。它把复杂的交叉检测工作交给了浏览器底层去优化,开发者只需要关注业务逻辑,大大降低了实现懒加载的复杂性和性能风险。

实现懒加载时可能遇到的坑和优化建议?

即便有了

IntersectionObserver
这样强大的工具,懒加载在实际应用中也并非一帆风顺,总有些“坑”等着你跳,或者有些细节能让体验更上一层楼。

常见的“坑”:

  1. 布局抖动 (CLS - Cumulative Layout Shift): 这是最常见也最令人头疼的问题之一。如果你的图片在加载前没有明确的宽度和高度(或者没有通过 CSS 设置
    aspect-ratio
    ),那么当图片加载完成后,它会占据实际的空间,导致其下方的所有内容向下“跳动”。这不仅影响用户阅读,也会严重拖累用户体验评分(Core Web Vitals 中的 CLS 指标)。想想你正在阅读一篇文章,突然图片一加载,文字就往下跳了一大截,那种感觉真的很糟糕。
  2. “闪烁”或空白: 在图片加载完成之前,如果
    src
    属性是一个空白或很小的占位符,用户可能会看到一块空白区域。如果网络较慢,这种空白时间会更长,给用户一种“内容缺失”的感觉。
  3. 首屏图片被懒加载: 很多时候,开发者会不加区分地给所有图片都加上懒加载。然而,对于首屏(Above-the-fold)可见的图片,它们应该被立即加载,而不是等待
    IntersectionObserver
    触发。如果首屏图片也懒加载,反而会延迟用户看到关键内容的时间。
  4. 无 JavaScript 降级: 如果用户禁用了 JavaScript,或者浏览器环境不支持
    IntersectionObserver
    (尽管现在这种情况越来越少),你的图片可能永远不会加载。

优化建议:

  1. 为图片设置明确的尺寸或
    aspect-ratio
    这是解决 CLS 的核心。在 HTML 中直接指定
    width
    height
    属性,或者使用 CSS 的
    padding-bottom
    技巧(结合
    position: absolute
    )来创建一个基于图片宽高比的占位符。现代 CSS 也可以直接使用
    aspect-ratio
    属性。
    @@##@@

    或者 CSS:

    .image-container {
        position: relative;
        width: 100%;
        padding-bottom: 75%; /* 4:3 宽高比,即 600/800 = 0.75 */
        height: 0;
        overflow: hidden;
    }
    .image-container img {
        position: absolute;
        top: 0;
        left: 0;
        width: 100%;
        height: 100%;
    }
  2. 使用模糊占位符或 LQIP (Low Quality Image Placeholder): 而不是一个纯空白的占位符,你可以加载一个非常小的、低质量的图片版本作为
    src
    ,然后当真实图片加载完成后再替换掉。这能极大地提升用户体验,因为即使图片还没完全加载,用户也能看到一个模糊的预览。
  3. 合理设置
    rootMargin
    IntersectionObserver
    的选项中,
    rootMargin
    参数非常有用。你可以设置一个负值或正值,让图片在进入视口前(比如提前 100px)就开始加载。这样可以避免用户滚动到图片位置时,图片才开始加载而出现的短暂空白。
    { rootMargin: '0px 0px 200px 0px' } // 底部提前200px加载
  4. 排除首屏图片: 对于那些确定会在页面加载时就显示出来的图片,直接使用
    src
    属性加载它们,不要应用懒加载逻辑。这可以通过手动标记,或者通过判断图片的位置来决定。
  5. 浏览器原生
    loading="lazy"
    属性:
    这是一个非常棒的补充方案。现代浏览器已经支持在
    @@##@@
    标签上直接使用
    loading="lazy"
    属性。它让浏览器自己决定何时加载图片,通常与
    IntersectionObserver
    类似。你可以将其作为第一层懒加载,然后用 JS 方案作为不支持
    loading="lazy"
    浏览器的降级。
    @@##@@

    注意,这种情况下,你可能就不需要

    data-src
    了,因为浏览器会自己处理。但如果需要更精细的控制,或者兼容性要求高,JS 方案依然是必要的。

  6. srcset
    sizes
    结合:
    懒加载不等于放弃响应式图片。结合
    srcset
    sizes
    属性,确保在懒加载时也能根据用户的设备屏幕大小和分辨率加载最合适的图片,进一步节省带宽。
  7. 渐进式图片加载: 对于大型图片,可以考虑使用渐进式 JPEG 或 WebP 格式,它们在下载过程中可以逐步显示图片内容,而不是等到完全下载后才显示。

处理这些细节,才能让图片懒加载真正发挥其性能优势,同时不牺牲用户体验。

js 怎么实现图片懒加载描述图片内容js 怎么实现图片懒加载js 怎么实现图片懒加载描述图片内容

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
线程和进程的区别
线程和进程的区别

线程和进程的区别:线程是进程的一部分,用于实现并发和并行操作,而线程共享进程的资源,通信更方便快捷,切换开销较小。本专题为大家提供线程和进程区别相关的各种文章、以及下载和课程。

525

2023.08.10

线程和进程的区别
线程和进程的区别

线程和进程的区别:线程是进程的一部分,用于实现并发和并行操作,而线程共享进程的资源,通信更方便快捷,切换开销较小。本专题为大家提供线程和进程区别相关的各种文章、以及下载和课程。

525

2023.08.10

js正则表达式
js正则表达式

php中文网为大家提供各种js正则表达式语法大全以及各种js正则表达式使用的方法,还有更多js正则表达式的相关文章、相关下载、相关课程,供大家免费下载体验。

515

2023.06.20

js获取当前时间
js获取当前时间

JS全称JavaScript,是一种具有函数优先的轻量级,解释型或即时编译型的编程语言;它是一种属于网络的高级脚本语言,主要用于Web,常用来为网页添加各式各样的动态功能。js怎么获取当前时间呢?php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

244

2023.07.28

js 字符串转数组
js 字符串转数组

js字符串转数组的方法:1、使用“split()”方法;2、使用“Array.from()”方法;3、使用for循环遍历;4、使用“Array.split()”方法。本专题为大家提供js字符串转数组的相关的文章、下载、课程内容,供大家免费下载体验。

320

2023.08.03

js是什么意思
js是什么意思

JS是JavaScript的缩写,它是一种广泛应用于网页开发的脚本语言。JavaScript是一种解释性的、基于对象和事件驱动的编程语言,通常用于为网页增加交互性和动态性。它可以在网页上实现复杂的功能和效果,如表单验证、页面元素操作、动画效果、数据交互等。

5330

2023.08.17

js删除节点的方法
js删除节点的方法

js删除节点的方法有:1、removeChild()方法,用于从父节点中移除指定的子节点,它需要两个参数,第一个参数是要删除的子节点,第二个参数是父节点;2、parentNode.removeChild()方法,可以直接通过父节点调用来删除子节点;3、remove()方法,可以直接删除节点,而无需指定父节点;4、innerHTML属性,用于删除节点的内容。

482

2023.09.01

js截取字符串的方法
js截取字符串的方法

js截取字符串的方法有substring()方法、substr()方法、slice()方法、split()方法和slice()方法。本专题为大家提供字符串相关的文章、下载、课程内容,供大家免费下载体验。

212

2023.09.04

C++ 设计模式与软件架构
C++ 设计模式与软件架构

本专题深入讲解 C++ 中的常见设计模式与架构优化,包括单例模式、工厂模式、观察者模式、策略模式、命令模式等,结合实际案例展示如何在 C++ 项目中应用这些模式提升代码可维护性与扩展性。通过案例分析,帮助开发者掌握 如何运用设计模式构建高质量的软件架构,提升系统的灵活性与可扩展性。

14

2026.01.30

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Sass 教程
Sass 教程

共14课时 | 0.8万人学习

Bootstrap 5教程
Bootstrap 5教程

共46课时 | 3.1万人学习

CSS教程
CSS教程

共754课时 | 25.5万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号