🚀 别再让浏览器“负重跑”了!手把手教你用 IntersectionObserver 实现图片懒加载

🚀 别再让浏览器"负重跑"了!手把手教你用 IntersectionObserver 实现图片懒加载


💡 前言:为什么你的网页打开像"PPT"?

想象一下,你正在约会,对面坐着一位美女(用户)。她满怀期待地问你:"嘿,你的网站快吗?"

然后你深吸一口气,开始从背包里往外掏东西:先掏出一张巨大的海报(首屏大图),然后是几百张高清无码的猫咪照片(长列表图片),最后还有几个G的视频......

美女(用户)看着你这一堆乱七八糟的东西,还没等你掏完,她就说了一句:"算了,我们不合适。" 然后转身走了(用户流失,跳出率 100%)。

这就是**不做懒加载(Lazy Load)**的下场。

在传统的网页开发中,我们习惯把所有 <img> 标签的 src 一股脑全写上。浏览器一看:"好家伙,老板发话了,不管三七二十一,全部下载!" 于是,即使用户根本还没滑到页面底部,浏览器就已经累得气喘吁吁,流量在燃烧,内存再尖叫。

今天,我们就来聊聊如何用现代浏览器的"外挂"------ IntersectionObserver,来拯救你那卡顿的网页。


🧐 什么是懒加载?

简单来说,就是**"按需加载"**。

  • 用户看哪里,就加载哪里。
  • 用户还没滑到的图片?先给个"占位符"(比如一张很轻的loading图或者灰色背景)糊弄一下。
  • 等用户快滑到了,再瞬间把真图换上。

这就好比你去自助餐厅,不会一次性把所有菜都堆在桌子上,而是吃一盘,拿一盘


🛠️ 实战:手写一个"丝滑"的懒加载

以前,我们要实现懒加载,得监听 window.onscroll 事件,然后疯狂计算 getBoundingClientRect,还要防抖节流......写起来简直头秃,性能还差。

现在,IntersectionObserver 来了!它是浏览器原生的 API,专门用来监听元素是否进入了视口(可视区域)。它运行在单独的线程中,性能极佳,简直是前端界的"德芙",纵享丝滑。

来看代码(结合你提供的示例):

html 复制代码
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>图片的懒加载</title>
  <style>
    * { margin: 0; padding: 0; }
    /* 搞几个大盒子把图片挤下去,模拟长页面 */
    .box { height: 200vh; background-color: #eee; } 
    img { width: 100%; height: 400px; object-fit: cover; display: block; }
  </style>
</head>
<body>

  <!-- 占位用的大盒子 -->
  <div class="box"></div>

  <!-- 
    1. src: 先放一张极小的默认图(或者loading图),防止页面布局塌陷
    2. data-src: 把真正的高清大图藏在这里,浏览器不会主动加载它
  -->
  <img class="lazy" 
       src="https://img10.360buyimg.com/wq/jfs/t24601/190/890984006/4559/731564fc/5b7f9b7bN3ccd29ab.png" 
       data-src="https://img.36krcdn.com/hsossms/20260119/v2_53cad3f2226f48e2afc1942de3ab74e4@5888275@ai_oswg1141728oswg1053oswg495_img_png~tplv-1marlgjv7f-ai-v3:960:400:960:400:q70.jpg?x-oss-process=image/format,webp" 
       alt="AI生图1">

  <div class="box"></div>

  <img class="lazy" 
       src="https://img10.360buyimg.com/wq/jfs/t24601/190/890984006/4559/731564fc/5b7f9b7bN3ccd29ab.png" 
       data-src="https://img.36krcdn.com/hsossms/20260117/v2_1e74add07bb94971845c777e0ce87a49@000000@ai_oswg421938oswg1536oswg722_img_000~tplv-1marlgjv7f-ai-v3:960:400:960:400:q70.jpg?x-oss-process=image/format,webp" 
       alt="AI生图2">

  <script>
    // 1. 选中所有需要懒加载的图片
    const images = document.querySelectorAll('.lazy');

    // 2. 创建观察者实例
    // 浏览器提供的观察者模式,自动观察,性能杠杠的
    const observer = new IntersectionObserver((entries) => {
      // entries 是一个数组,包含所有被观察元素的状态
      entries.forEach(entry => {
        // isIntersecting 为 true 表示元素进入了视口
        if (entry.isIntersecting) {
          const img = entry.target; // 获取目标元素 (DOM节点)
          const original_img = img.dataset.src; // 获取 data-src 里的真图地址
          
          console.log('抓到你了!正在加载:', original_img);
          
          // 3. 偷梁换柱:把真图地址赋值给 src
          img.src = original_img;
          
          // 4. 加载完后,告诉观察者:"这人看过了,不用盯着了"
          // 停止观察该元素,节省性能
          observer.unobserve(img);
        }
      })
    })

    // 5. 开始观察!
    images.forEach(img => observer.observe(img));
  </script>
</body>
</html>

🔍 代码核心知识点解析

别光顾着复制粘贴,我们来拆解一下这里的"骚操作":

  1. data-src 的妙用 🎭 HTML 标准规定,<img> 标签只要有 src 属性,浏览器就会立刻发起请求。为了阻止这个行为,我们把真实的图片链接藏在自定义属性 data-src 里。浏览器:"哦,这只是一个叫 data-src 的字符串,我不认识,不加载。"

  2. IntersectionObserver API 👁️ 这是主角。

    • 传统做法:你得不停地问浏览器"图片在哪?滚动条在哪?算一下距离......"(强制重排/重绘,累死CPU)。
    • IntersectionObserver:你告诉浏览器"帮我盯着这张图,它出来了叫我一声"。浏览器在底层异步处理这些计算,完全不影响页面渲染帧率。
  3. entry.isIntersecting ✅ 这是一个布尔值。true 代表元素和视口有交集(出现了),false 代表没交集(消失了)。我们在 true 的时候才去加载图片。

  4. observer.unobserve(img) 🛑 这点很重要!图片加载完了,任务就结束了。如果不取消观察,浏览器还会一直盯着这张已经加载好的图片,纯属浪费资源。用完即弃,才是好代码。


🤔 为什么要这么做?(必要性)

你可能会问:"我就几张图,直接加载不行吗?"

  • 首屏速度(First Contentful Paint):用户打开网页,只关心第一屏。如果后台在偷偷下载第10屏的图片,首屏加载就会变慢。懒加载能让首屏飞起来。
  • 节省带宽:很多用户可能根本不会滑到底部。你加载了100张图,他只看了10张。懒加载帮他省了90%的流量,他会感谢你的(特别是用5G流量看视频的时候)。
  • 减少内存占用:浏览器同时处理几百个网络请求和渲染几百张大图,内存容易爆炸,导致页面卡顿甚至崩溃。

📌 总结

懒加载是现代 Web 开发的标配

以前我们用 jQuery 写插件,后来用原生 JS 算坐标,现在我们有了 IntersectionObserver。技术总是在进步,我们要学会用更优雅、性能更好的方式去解决问题。

下次再有人问你网站为什么这么快,你可以淡淡地喝一口咖啡,说:"哦,我只是让我的图片学会了'按需出现'而已。"

Happy Coding! ☕️


(本文代码已在 Chrome/Firefox/Edge 等现代浏览器测试通过。IE 用户?请出门右转不送,或者加个 Polyfill 吧。)

相关推荐
胖纳特2 小时前
从零到一:OnlyOffice中国版企业级完整落地指南
前端·后端
jrlong2 小时前
HelloAgents 进阶篇 task03
java·前端·python
搬砖的前端2 小时前
本地模型+TRAE CN 打造最优模型组合实测:开源主模型+本地辅模型,对标GPT5.2/5.3/Gemini-3-Flash
前端·ai·mac·ai编程·qwen·trae·qwen3.6
talen_hx2962 小时前
飞书机器人发文本消息
java·前端·飞书
freewlt2 小时前
前端工程化性能监控体系建设:从0到1实战指南
前端
Mintopia2 小时前
别再一上来就分层:新手最容易做错的系统设计决定
前端
Csvn2 小时前
CDN 与缓存策略
前端
Mintopia2 小时前
不用死磕高并发,也能扛住流量:简单实用的系统设计思路
前端
rADu REME2 小时前
rust web框架actix和axum比较
前端·人工智能·rust