跳到主要内容
极客日志极客日志面向AI+效率的开发者社区
首页博客GitHub 精选镜像工具UI配色美学隐私政策关于联系
搜索内容 / 工具 / 仓库 / 镜像...⌘K搜索
注册
博客列表
JavaScript大前端

前端基于 IntersectionObserver 的流畅懒加载实现

综述由AI生成介绍如何使用 IntersectionObserver API 在前端实现流畅的懒加载功能。通过监听元素可见性变化,在滚动到底部时自动加载下一页数据,替代传统的 scroll 事件监听。代码示例展示了 React 中结合 useRef 和 useEffect 的实现细节,包括首次加载保护、rootMargin 配置及数据追加逻辑。相比 scroll 事件,该方法性能更优且不阻塞主线程,适用于列表页、图片墙等场景。

虚拟内存发布于 2026/3/28更新于 2026/5/3024 浏览
前端基于 IntersectionObserver 的流畅懒加载实现

一、什么是 IntersectionObserver?

IntersectionObserver 是浏览器原生提供的一个可观察元素可见性变化的 API。简单来说,它能帮我们'监听'某个元素是否出现在视口中。

当元素进入或离开视口时,回调函数会被触发。

核心优势:

  • 不需要监听 scroll 事件;
  • 浏览器原生支持,性能更好;
  • 可配置 rootMargin(提前加载距离);
  • 异步执行,不阻塞主线程。

二、懒加载的常见应用场景

  • 图片懒加载:只有当图片进入视口时才加载资源;
  • 无限滚动列表:当滚动到底部时,自动加载下一页;
  • 广告曝光监测:检测广告区域是否被用户看到。

本文聚焦第二种:滚动到底部自动加载更多数据。

三、功能目标

我们的目标是构建一个'廉政制度'页面,当用户滚动到列表底部时自动加载下一页数据。

主要功能包括:

  1. 初次加载数据
  2. 输入关键词搜索
  3. 滚动到底部触发加载更多
  4. 防止首次渲染误触发
  5. 数据加载完成后关闭加载提示

四、核心实现代码

来看关键部分的实现逻辑(已省略部分业务代码):

import { useEffect, useState, useRef, useCallback } from "react";
import { getEthicsRegulationList } from "../../api/backendApi";

function PolicyList() {
  const [regulations, setRegulations] = useState([]);
  const [page, setPage] = useState(0);
  const [hasMore, setHasMore] = useState(true);
  const observerRef = useRef(null);
  const firstLoadRef = useRef(true); // ✅ 初次加载保护标志

  // 获取数据
  const fetchData = useCallback(async (reset = false) => {
    const res = await getEthicsRegulationList({ page, size: 7 });
    if (reset) {
      setRegulations(res.content || []);
    } else {
      setRegulations((prev) => [...prev, ...(res.content || [])]);
    }
    setHasMore(!res.last);
  }, [page]);

  // 初始化加载
  useEffect(() => {
    fetchData(true);
  }, []);

  // IntersectionObserver 实现懒加载
  useEffect(() => {
    if (!observerRef.current) return;
    const observer = new IntersectionObserver((entries) => {
      const entry = entries[0];
      // ✅ 避免第一次渲染时触发加载
      if (entry.isIntersecting && hasMore && !firstLoadRef.current) {
        setPage((prev) => prev + 1);
      }
    }, { rootMargin: "100px" }); // 提前 100px 触发加载
    observer.observe(observerRef.current);
    return () => observer.disconnect();
  }, [hasMore]);

  // 页码变化时加载下一页
  useEffect(() => {
    if (page === 0) return;
    fetchData();
  }, [page]);

  // 首次加载完成后,关闭'首次加载保护'
  useEffect(() => {
    if (regulations.length > 0) {
      firstLoadRef.current = false;
    }
  }, [regulations]);

  return (
    <div className="policy-list">
      {regulations.map((item, index) => (
        <div key={index} className="policy-card">{item.title}</div>
      ))}
      {/* 观察点(加载触发点) */}
      <div ref={observerRef} className="loading-more">
        {hasMore ? "加载更多..." : "已加载全部"}
      </div>
    </div>
  );
}

export default PolicyList;

五、实现思路拆解

1. 设置观察目标

我们在列表底部放置一个空的 <div>:

<div ref={observerRef} className="loading-more"></div>

这个元素就是'触发点'——当它出现在视口中时,就意味着用户滚动到底部。

2. 创建 IntersectionObserver 实例
const observer = new IntersectionObserver((entries) => {
  const entry = entries[0];
  if (entry.isIntersecting && hasMore) {
    setPage((prev) => prev + 1);
  }
}, { rootMargin: "100px" });
  • entries[0].isIntersecting:表示目标元素是否进入视口;
  • rootMargin:设置'提前加载'的距离;
    • 例如 "100px" 表示当元素距离视口底部 100px 时就触发。
3. 首次加载保护

首次渲染时,观察目标往往默认可见,会误触发加载。

因此使用一个 useRef 标记:

const firstLoadRef = useRef(true);
useEffect(() => {
  if (regulations.length > 0) {
    firstLoadRef.current = false;
  }
}, [regulations]);

在懒加载逻辑中增加判断:

if (entry.isIntersecting && hasMore && !firstLoadRef.current) {
  setPage((prev) => prev + 1);
}
4. 页码变化时加载下一页
useEffect(() => {
  if (page === 0) return; // 初次加载已处理
  fetchData();
}, [page]);

当 page 变化时重新请求数据,并将结果追加到已有数据中。

六、rootMargin 的妙用

rootMargin 是懒加载的'提前量'。假设设置为 "100px",意味着当底部触发点距离视口底部还有 100px 时就开始加载,避免滚动到底才触发、用户等待的卡顿感。

总结

对比项IntersectionObserverscroll 事件监听
性能异步执行,浏览器优化高频触发,需手动节流
可维护性简洁明了,配置灵活逻辑复杂
支持性现代浏览器原生支持所有浏览器通用

💬 懒加载并不只是'少加载',而是让'用户感觉快'。

这才是现代前端性能优化的核心思想。

目录

  1. 一、什么是 IntersectionObserver?
  2. 二、懒加载的常见应用场景
  3. 三、功能目标
  4. 四、核心实现代码
  5. 五、实现思路拆解
  6. 1. 设置观察目标
  7. 2. 创建 IntersectionObserver 实例
  8. 3. 首次加载保护
  9. 4. 页码变化时加载下一页
  10. 六、rootMargin 的妙用
  11. 总结
  • 💰 8折买阿里云服务器限时8折了解详情
  • Magick API 一键接入全球大模型注册送1000万token查看
  • 🤖 一键搭建Deepseek满血版了解详情
  • 一键打造专属AI 智能体了解详情
极客日志微信公众号二维码

微信扫一扫,关注极客日志

微信公众号「极客日志V2」,在微信中扫描左侧二维码关注。展示文案:极客日志V2 zeeklog

更多推荐文章

查看全部
  • 数据结构核心:树与堆的概念及存储实现
  • MySQL 覆盖索引:原理、优势与适用场景
  • Stack-Chan 机器人开发与使用指南
  • Ghidra 开源逆向分析工具详解
  • OpenClaw AI Agent 实战指南:橙皮书与蓝皮书核心内容解析
  • 基于 AI 辅助的 Java 在线考试系统开发实践
  • Zotero 插件接入 DeepSeek AI 实现文献智能分析配置指南
  • Vivado 2023.2 安装教程:从零搭建 FPGA 开发环境
  • Llama.cpp 部署教程:老旧电脑运行大模型方案
  • KingbaseES 内核级 SQL 防火墙:白名单防护与零误报实践
  • Docker 拉取镜像超时解决方案:配置镜像加速器及隐藏设置
  • OpenClaw 飞书机器人配置指南:多渠道 AI 助手集成
  • 机器人调度系统交通管制与路径规划算法详解
  • 使用 OpenClaw 自动化发布 AI 新闻至微信与小红书
  • Faster-Whisper 本地实时语音识别部署与实战指南
  • 5 分钟切换不同 AI 引擎:Codex 多模型支持实战指南
  • YOLOv11 数据集训练、推理及网络结构详解
  • YOLO 算法进阶提升:骨干网络、特征融合与损失函数改进
  • 伺服驱动器 FPGA 架构实现:电流环 速度环 位置环及 SVPWM 设计
  • SHCTF 3rd Web 部分题目 Writeup

相关免费在线工具

  • Keycode 信息

    查找任何按下的键的javascript键代码、代码、位置和修饰符。 在线工具,Keycode 信息在线工具,online

  • Escape 与 Native 编解码

    JavaScript 字符串转义/反转义;Java 风格 \uXXXX(Native2Ascii)编码与解码。 在线工具,Escape 与 Native 编解码在线工具,online

  • JavaScript / HTML 格式化

    使用 Prettier 在浏览器内格式化 JavaScript 或 HTML 片段。 在线工具,JavaScript / HTML 格式化在线工具,online

  • JavaScript 压缩与混淆

    Terser 压缩、变量名混淆,或 javascript-obfuscator 高强度混淆(体积会增大)。 在线工具,JavaScript 压缩与混淆在线工具,online

  • Base64 字符串编码/解码

    将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online

  • Base64 文件转换器

    将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online