当前位置: 首页 > news >正文

IntersectionObserver API

1.基本语法

const observer = new IntersectionObserver(callback, options)

2.参数说明

参数1:callback - 回调函数

(entries) => {entries.forEach((entry) => {// entry 包含被观察元素的信息})
}

entries 是一个数组,包含所有状态变化的元素信息
每个 entry 对象包含:

entry = {target: Element,              // 被观察的 DOM 元素isIntersecting: boolean,      // 是否与根元素相交(是否可见)intersectionRatio: number,     // 相交比例(0-1)boundingClientRect: DOMRect,  // 元素的位置信息rootBounds: DOMRect,          // 根元素的位置信息intersectionRect: DOMRect,     // 相交区域的位置信息time: number                  // 时间戳
}

参数2:options - 配置对象

{root: null,                    // 根元素(视口或指定容器)rootMargin: '0px',            // 根元素的边距threshold: [0, 1]              // 触发阈值
}
  • 指定一个 容器元素 作为 “观察基准”,目标元素是否 “进入”,取决于是否和这个容器重叠。
    • 默认值 null:参照区域是 浏览器视口(整个页面的可见区域);
    • 必须满足:root 必须是目标元素的 祖先元素(比如目标元素在某个滚动容器里,才能把这个容器设为 root)。
    •   // 例子:监听元素是否进入「自定义滚动容器」(而非整个页面)const scrollContainer = document.getElementById('侧边栏滚动容器');const options = {root: scrollContainer, // 参照区域 = 侧边栏容器,不是整个页面rootMargin: '0px',threshold: 0};
      
  • rootMargin: ‘0px’ → 扩展 / 缩小 “参照区域”(提前 / 延后触发)
    • 作用:给 root(参照区域)加 “虚拟边距”,相当于 放大或缩小判断的 “触发范围”,让回调提前或延后触发。
    • 格式和 CSS margin 完全一致:上 右 下 左(比如 100px 0 50px 0);支持 px 或 %,不能用 auto;
    • 正值 = 扩大参照区域(提前触发),负值 = 缩小参照区域(延后触发)。
  • threshold: 0 → 定义 “交叉比例”(触发的临界值)
    • 作用:指定目标元素与 root(参照区域)的 重叠比例 达到多少时,触发回调。
    • 取值范围:0 ~ 1(0 = 无重叠,1 = 完全重叠);可以是单个数字(比如 0.5),也可以是数组(比如 [0, 0.5, 1] → 重叠 0%、50%、100% 时各触发一次);默认值 0:目标元素 刚碰到 参照区域(重叠比例 > 0)就触发
    • 场景 1(滚动动画):希望元素 显示一半以上 时再触发动画,避免刚露个边就动:
    const options = {root: null,rootMargin: '0px',threshold: 0.5 // 重叠比例≥50%才触发
    };	
    
    • 场景 3(多阶段触发):需要知道元素 “进入、过半、完全进入” 三个状态:
       const options = {threshold: [0, 0.5, 1] // 三个阈值,触发三次回调};
    

回调中可通过 entry.intersectionRatio 判断当前是哪个阶段

3.方法

observe(element) - 开始观察

observer.observe(element)  // 开始观察一个元素

unobserve(element) - 停止观察

observer.unobserve(element)  // 停止观察一个元素

disconnect() - 断开所有观察

observer.disconnect()  // 停止观察所有元素,并清理观察器

4.使用示例

4.1.基础用法

// 创建观察器
const observer = new IntersectionObserver((entries) => {entries.forEach((entry) => {if (entry.isIntersecting) {console.log('元素进入视口:', entry.target)} else {console.log('元素离开视口:', entry.target)}})
}, {root: null,threshold: 0.5
})

4.2.懒加载图片

const imageObserver = new IntersectionObserver((entries) => {entries.forEach((entry) => {if (entry.isIntersecting) {const img = entry.targetimg.src = img.dataset.src  // 加载真实图片imageObserver.unobserve(img)  // 加载后停止观察}})
})document.querySelectorAll('img[data-src]').forEach(img => {imageObserver.observe(img)
})

4.3.无限滚动

const loadMoreObserver = new IntersectionObserver((entries) => {entries.forEach((entry) => {if (entry.isIntersecting) {loadMoreContent()  // 加载更多内容}})
}, {root: null,rootMargin: '100px'  // 提前 100px 触发
})const sentinel = document.querySelector('.load-more-sentinel')
loadMoreObserver.observe(sentinel)

4.4.锚点动态

// 观察多个锚点元素
observer = new IntersectionObserver((entries) => {entries.forEach(entry => {// 更新每个锚点的可见状态const name = entry.target.getAttribute('act-anchor-name')observedMap.set(name, { isIntersecting: entry.isIntersecting  // 是否可见})})// 找到最接近视口顶部的可见锚点// 通知所有 Portal 更新激活状态
})

5.浏览器兼容性

现代浏览器:Chrome 51+、Firefox 55+、Safari 12.1+、Edge 15+
如需支持旧浏览器,可使用 polyfill

6.对比

6.1传统懒加载

“传统懒加载”,核心是通过 监听 scroll 事件 + 计算元素位置 实现;而 IntersectionObserver 是浏览器原生提供的 “交叉状态监听 API”。两者的核心差异集中在 性能、代码复杂度、功能灵活性 上

  1. 传统懒加载(scroll + resize + getBoundingClientRect)
  • 原理:通过监听页面滚动(scroll)、窗口大小变化(resize)等事件,在事件回调中 手动计算目标元素的位置,判断是否进入视口。
  • 核心步骤:
    • 给 window 绑定 scroll、resize 事件(高频触发);
    • 事件回调中,用 element.getBoundingClientRect() 获取元素的坐标(top/left 等);
    • 对比元素坐标与视口大小(window.innerHeight/window.innerWidth),判断是否进入视口;
    • 若进入视口,加载真实资源(如替换图片 src)。
      传统懒加载代码示例(简化版):
<img class="lazy" src="placeholder.png" data-src="real.jpg" alt="示例">
<script>
// 1. 监听 scroll/resize 事件(需防抖优化,否则性能极差)
function debounce(fn, delay = 100) {let timer;return () => clearTimeout(timer) || (timer = setTimeout(fn, delay));
}// 2. 手动计算元素是否进入视口
function checkLazyLoad() {document.querySelectorAll('.lazy').forEach(img => {const rect = img.getBoundingClientRect();// 条件:元素顶部 ≤ 视口高度(进入视口)const isInView = rect.top <= window.innerHeight && rect.bottom >= 0;if (isInView) {img.src = img.dataset.src; // 加载真实图片img.classList.remove('lazy'); // 避免重复检查}});
}// 3. 绑定事件(防抖优化后)
window.addEventListener('scroll', debounce(checkLazyLoad));
window.addEventListener('resize', debounce(checkLazyLoad));
// 初始化时检查一次
checkLazyLoad();
</script>
  1. IntersectionObserver 懒加载
  • 原理:浏览器原生异步监听目标元素与 “根元素”(默认视口)的 交叉状态,无需手动监听 scroll/resize,也不用手动计算位置 —— 浏览器直接告诉我们 “元素是否进入视口”。
  • 核心步骤:
    • 创建 IntersectionObserver 实例,配置监听规则(根元素、边距、阈值);
    • 用 observe() 监听目标元素;
    • 元素交叉状态变化时,浏览器触发回调,在回调中加载真实资源。
<img class="lazy" src="placeholder.png" data-src="real.jpg" alt="示例">
<script>
// 1. 创建观察器,配置规则(提前200px加载)
const observer = new IntersectionObserver((entries) => {entries.forEach(entry => {if (entry.isIntersecting) { // 浏览器直接判断:元素进入视口const img = entry.target;img.src = img.dataset.src; // 加载真实图片observer.unobserve(img); // 停止监听,避免重复触发}});
}, { rootMargin: '200px 0' }); // 提前200px加载// 2. 监听所有懒加载图片
document.querySelectorAll('.lazy').forEach(img => observer.observe(img));
</script>

在这里插入图片描述

优劣原因

1. 为什么是 “异步监听,不阻塞主线程”?

  • 传统 scroll 方案的问题:

    • scroll 是 “同步事件”,只要用户滚动页面,事件就会 高频触发(每秒几十次),且所有回调逻辑都在 主线程 执行
    • 主线程要一边处理你的 scroll 回调(计算元素位置),一边还要处理其他 JS、渲染页面、响应用户操作;
    • 一旦回调逻辑复杂(比如遍历多个元素计算位置),主线程就会被 “占满”,导致页面卡顿(比如滚动不流畅、点击没反应)。
  • IntersectionObserver 的设计:“后台专人盯防”

    • IntersectionObserver 是 浏览器原生的异步 API,工作流程完全不占用主线程:
    • 你创建观察器时,相当于告诉浏览器:“帮我盯着这些元素,它们和根元素交叉状态变了就告诉我”;浏览器把这个 “监听任务” 交给了 合成线程(后台线程),主线程直接 “解放”,该干嘛干嘛(执行其他 JS、渲染页面);
    • 只有当元素真的进入 / 离开视口(交叉状态变化)时,合成线程才会通过 “异步消息” 通知主线程,触发回调。简单说:传统方案是 “你自己每秒跑几十次去检查”,IntersectionObserver 是 “雇了个后台专人,有情况才告诉你”—— 主线程自然不会被阻塞。

2. 为什么 “交叉状态计算由浏览器底层完成,不会触发重排”?

  • 先搞懂:什么是 “重排”?为什么传统方案会触发?
    • 重排(Reflow):浏览器重新计算页面元素的位置、大小,是性能开销极大的操作(比如修改 width、调用 getBoundingClientRect() 都会触发);
    • 传统方案的 getBoundingClientRect():每次调用都会让浏览器 “重新计算元素的实时位置”,必然触发重排 —— 而你在 scroll 回调里每秒调用几十次,相当于每秒强制浏览器重排几十次,页面不卡才怪!
  • IntersectionObserver 的计算逻辑:“复用现成数据,不额外折腾”
    • 浏览器的合成线程在处理 “滚动” 时,本身就需要知道所有元素的位置信息(才能正确渲染滚动后的页面)——IntersectionObserver 直接 “复用” 了这些现成的位置数据,完全不需要额外计算:
    • 合成线程维护着一个 “图层树”(记录所有元素的位置、大小、层级),滚动时会实时更新这个树;它判断 “目标元素是否和根元素交叉”,只需要对比图层树里的两个元素坐标不需要修改 DOM、不需要重新计算布局
      整个计算过程在合成线程内部完成,完全不涉及主线程的 “重排” 逻辑。
    • 简单说:传统方案是 “每次都让浏览器重新算一遍位置(重排)”,IntersectionObserver 是 “浏览器本来就知道位置,只是顺便帮你对比一下”—— 自然不会触发重排。
http://www.dtcms.com/a/618879.html

相关文章:

  • 陕西煤业化工建设集团有限公司网站网站建设如何选择良好的服务器
  • 贵阳高端网站开发制作做网站应该画什么图
  • 深入浅出Ansible循环语句:从基础到实践
  • 沧州北京网站建设营销 网站制作
  • 徐州10年网站建设 推广公司wordpress 明星主题
  • 修复Ubuntu系统文件损坏问题:手动fsck指令
  • 手动监控3小时?RPA实时追踪小红书关键词排名,效率提升2000%[特殊字符]
  • 网站怎么做响应式番禺做网站最便宜的哪家公司
  • 创建站点的步骤微信小游戏怎么开发
  • K8S学习笔记:基本概念
  • MYSQL的所有基础操作
  • 张家港网站推广自己在线制作logo免费模版
  • 网站后台用什么语言恩施做网站多少钱
  • LeetCode100--22. 括号生成
  • LeetCode 分类刷题:1669. 合并两个链表
  • 什么是JMeter?如何用JMeter做性能测试?
  • 高端装饰公司网站设计昆山网站建设首页
  • 河南省住房和城乡建设部网站首页郑州网站关键词优化外包
  • spring学习笔记之注解开发
  • 中药饮片批发商是什么?其在中药供应链中的意义和作用是什么?
  • 鲜花销售|花店销售|基于java+vue的鲜花销售系统设计与实现(源码+数据库+文档)
  • 什么是h5网站如何在服务器里建设网站
  • 最便宜的低价机票网站建设附近临时工500元一天
  • SHA-256的初始哈希值是怎么规定的?
  • 做视频添加字幕的网站wordpress 获取导航栏
  • 建立网站数据库实验报告徐州设计公司有哪些
  • 专业网站公司本地佛山企业网站建设
  • 网页设计模板素材网站做一个招聘信息的网站 用什么做网站的软件
  • 【Spring Boot】基于MyBatis的条件分页
  • LVS负载均衡群集(二)-- DR模式