当前位置:首页 > 文章列表 > 文章 > 前端 > IntersectionObserver 怎样按可见性加载内容

IntersectionObserver 怎样按可见性加载内容

来源:17golang原创 2026-10-21 18:10:25 0浏览 收藏

如果页面先把所有图片、推荐卡片或下一页数据都加载进来,首屏会为用户暂时看不到的内容付出请求和渲染成本。IntersectionObserver 可以异步观察目标与视口(或指定滚动容器)的交集,在可见性跨过阈值时调用回调。按可见性加载的关键不是监听每一次滚动,而是把“什么时候算接近”写进观察器配置。

本文只讨论观察阈值、预加载距离和取消观察。打开弹窗、分页接口鉴权等业务逻辑仍由页面自己的交互层负责。

IntersectionObserver 目标内容与视口交集比例及阈值说明图

先确定什么叫“进入可见区域”

构造器的第二个参数决定观察边界。root: null 表示使用顶层文档视口;如果目标在一个独立滚动容器中,则把该容器传给 root。rootMargin 会扩大或收缩用于计算的根区域,适合让图片在真正进入屏幕前提前请求。threshold 是交集比例阈值,可以是一个数字,也可以是数组。

const observerOptions = {
  // null 表示使用浏览器视口;滚动容器场景应传入容器元素。
  root: null,
  // 提前 240px 触发加载,避免用户滚到图片时才开始请求。
  rootMargin: "240px 0px",
  // 只要目标与观察区域有交集,就触发一次回调。
  threshold: 0
};

const observer = new IntersectionObserver((entries) => {
  // 回调可能同时收到多个目标,只处理已经进入观察区域的目标。
  for (const entry of entries) {
    if (!entry.isIntersecting) continue;
    console.log("目标接近视口", entry.target);
  }
}, observerOptions);

默认阈值是 0,常用于“刚刚碰到观察区域就开始加载”。如果需要在内容至少显示一半时才执行曝光统计,可以使用 threshold: 0.5;如果需要观察多个阶段,则写成 [0, 0.25, 0.5, 1]。观察器创建后配置不能直接修改,想换阈值需要重新创建 observer。

用 data-src 把加载动作放进回调

一个 observer 可以观察多个目标,不需要每张图片都创建一个实例。将真实地址放在 data-src 中,等目标进入区域后再复制到 src,并在处理成功后取消这个目标的观察。

文章封面数据图表
const lazyObserver = new IntersectionObserver((entries, currentObserver) => {
  for (const entry of entries) {
    // isIntersecting 为 false 时只代表目标离开,不重复发起加载。
    if (!entry.isIntersecting) continue;

    const image = entry.target;
    const source = image.dataset.src;
    if (!source) {
      // 没有待加载地址时停止观察,避免无意义的回调。
      currentObserver.unobserve(image);
      continue;
    }

    // 把真实地址交给浏览器,加载完成后该目标无需继续观察。
    image.src = source;
    image.removeAttribute("data-src");
    currentObserver.unobserve(image);
  }
}, {
  // 让图片提前进入加载窗口,数值要结合图片大小与网络延迟调整。
  rootMargin: "240px 0px",
  threshold: 0
});

document.querySelectorAll(".lazy-image").forEach((image) => {
  // 使用同一个观察器管理所有懒加载图片。
  lazyObserver.observe(image);
});

这里的 unobserve(image) 只移除当前图片,不会影响其他目标。若图片加载失败仍要显示错误占位,可以在 image.onerror 中记录状态,再决定是否保留 data-src;不要因为网络失败就无条件重复设置 src。

threshold 和 rootMargin 不是一回事

threshold 描述“目标有多少比例与根区域相交时通知我”,而 rootMargin 描述“计算相交时把根区域扩大或收缩多少”。懒加载通常把 threshold 保持为 0,通过 rootMargin 给网络请求留提前量;曝光统计则更适合使用较高 threshold,避免只露出一条边就算作看见。

需求建议配置触发含义
图片提前加载threshold: 0、rootMargin: "240px 0px"进入扩大后的观察区域就加载
卡片显示一半再统计threshold: 0.5交集比例跨过 50% 时通知
滚动容器内加载root: scrollPanel以容器的可视区域而不是窗口判断

需要注意,IntersectionObserver 适合回答“是否达到某个比例”,不适合回答精确重叠了多少像素,也不保证回调在滚动事件的同一时刻同步执行。加载逻辑应当具备幂等性,不要假设回调只会收到一个 entry。

IntersectionObserver 从创建、观察、进入视口到取消观察的生命周期说明图

用 unobserve 和 disconnect 收好生命周期

单个目标完成加载后调用 unobserve(target),可以让 observer 继续服务其他图片。组件整体卸载时调用 disconnect(),一次停止它正在观察的全部目标。后者适合路由切换或组件销毁,不适合每加载一张图片就调用。

function createLazyLoader(container) {
  const targets = container.querySelectorAll("[data-src]");
  const loader = new IntersectionObserver((entries, currentObserver) => {
    for (const entry of entries) {
      if (!entry.isIntersecting) continue;

      const target = entry.target;
      // 只消费一次数据地址,避免同一目标重复请求。
      target.src = target.dataset.src;
      delete target.dataset.src;
      currentObserver.unobserve(target);
    }
  }, { rootMargin: "200px 0px", threshold: 0 });

  targets.forEach((target) => loader.observe(target));

  return () => {
    // 组件卸载时统一释放所有观察关系。
    loader.disconnect();
  };
}

const stopLazyLoading = createLazyLoader(document.querySelector(".article"));
// 路由或组件销毁时调用 stopLazyLoading()。

如果一个目标在首屏内,观察器通常会很快给出初始通知;不要把“已经在视口内”当成异常。对于动态追加的卡片,只需要在追加后对新节点调用同一个 observer 的 observe(),不必重新观察整个列表。

上线前记住四个边界

  • 先决定根是视口还是滚动容器;目标必须处在指定 root 的可观察关系中。
  • 懒加载优先用小 threshold 配合适度 rootMargin,提前量要按资源体积和网络延迟调整。
  • 回调遍历全部 entries,加载成功后对单个目标调用 unobserve();组件销毁时再调用 disconnect()。
  • 对不支持 IntersectionObserver 的环境保留简单降级:直接使用真实 src,或在能力检测后加载兼容方案。
if ("IntersectionObserver" in window) {
  // 支持时启用按可见性加载。
  startLazyLoading();
} else {
  // 不支持时直接显示内容,保证功能优先于性能优化。
  document.querySelectorAll("[data-src]").forEach((image) => {
    image.src = image.dataset.src;
  });
}

常见问题

为什么设置 threshold: 0 后没有立刻加载

threshold 只描述交集比例,不负责扩大观察范围。检查目标是否已经调用 observe()、root 是否正确,以及目标是否被隐藏;如果希望提前加载,增加 rootMargin。

目标离开视口后会再次请求吗

如果仍在观察且回调没有设置幂等条件,目标再次进入时可能再次执行逻辑。把地址放在 data-src、成功后删除它,并在完成处理后 unobserve,可以避免重复请求。

什么时候用 disconnect 而不是 unobserve

只想停止一个目标时用 unobserve;整个列表或组件不再存在时用 disconnect。两者都不会替你取消已经发出的网络请求,网络请求的取消需要由 Fetch 或资源加载逻辑单独处理。

参考资料:https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API、https://developer.mozilla.org/en-US/docs/Web/API/IntersectionObserver。

版本声明
本文转载于:17golang原创 如有侵犯,请联系study_golang@163.com删除
CSS anchor positioning 怎样让下拉菜单跟随触发按钮并自动避让边缘CSS anchor positioning 怎样让下拉菜单跟随触发按钮并自动避让边缘
上一篇
CSS anchor positioning 怎样让下拉菜单跟随触发按钮并自动避让边缘
JavaScript import attributes 怎样加载 JSON 模块
下一篇
JavaScript import attributes 怎样加载 JSON 模块
查看更多
最新文章
查看更多
课程推荐
  • 前端进阶之JavaScript设计模式
    前端进阶之JavaScript设计模式
    设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
    543次学习
  • GO语言核心编程课程
    GO语言核心编程课程
    本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
    516次学习
  • 简单聊聊mysql8与网络通信
    简单聊聊mysql8与网络通信
    如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
    500次学习
  • JavaScript正则表达式基础与实战
    JavaScript正则表达式基础与实战
    在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
    487次学习
  • 从零制作响应式网站—Grid布局
    从零制作响应式网站—Grid布局
    本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
    485次学习
查看更多
AI推荐
  • PubMedQA数据集详解:生物医学问答基准、功能与应用指南
    PubMedQA
    深入了解PubMedQA生物医学问答数据集,涵盖其核心功能、使用方法及在临床决策、药物研发等场景的应用,助力提升NLP模型性能。
    581次使用
  • H2O EvalGPT:开源LLM大模型评估与排行榜工具
    H2O EvalGPT
    H2O EvalGPT是H2O.ai推出的开源LLM评估平台,提供详细的大模型性能排行榜、行业特定基准测试及A/B测试功能,助您快速选择最适合项目的高性能大语言模型。
    620次使用
  • LMArena是什么?伯克利AI模型评估平台使用指南与功能解析
    LMArena
    LMArena是加州大学伯克利分校推出的AI模型匿名评测平台。通过盲测投票机制,用户可对比不同大模型回答并生成实时排行榜,助力开发者优化模型及用户选择最佳AI工具。
    651次使用
  • 斯坦福HELM:大语言模型Holistic Evaluation整体评估框架详解
    HELM
    深入了解斯坦福推出的HELM(Holistic Evaluation of Language Models)大模型评测体系。本文解析其核心功能、安装配置步骤及应用场景,涵盖准确性、公平性、鲁棒性等多维度指标,助力开发者全面优化语言模型性能。
    616次使用
  • MMBench详解:多模态大模型基准测试、功能特点与使用指南
    MMBench
    MMBench是由上海人工智能实验室等机构联合推出的多模态基准测试平台,提供细粒度能力评估、大规模数据集及VLMEvalKit工具。本文详细介绍其核心功能、安装使用方法及应用场景,助力开发者全面评估多模态模型性能。
    432次使用
微信登录更方便
  • 密码登录
  • 注册账号
登录即同意 用户协议 和 隐私政策
返回登录
  • 重置密码