大白话详解Intersection Observer API
昨天我写了Vue2 中自定义图片懒加载指令这篇博客,文章数据很好,阅读量可以上千,对于我这个刚写博客一周的新博主来说,是何等的荣幸。
所以在此我要感谢所有的读者与编程这个大家庭,是你们肯定了我,让我有了学习和写博客的动力。
那现在就来更新今天的文章吧,继续延续昨天的文章,昨天的文章有朋友在评论区推荐了Intersection Observer API
来实现图片懒加载,那这篇博客我先介绍一下这 API,但这 API 兼容性一般,且完全不兼容 IE,大家在实际项目中谨慎使用。
但在介绍Intersection Observer API之前,首先要先了解另外三个知识点,分别是 IntersectionObserver()构造器,IntersectionObserverEntry 对象与IntersectionObserverEntry 对象。
他们之前的关系比较复杂,大家可以先看看这个整体关系图,以及他们的参数、属性与方法。
1.Intersection Observer API 的基本介绍
Intersection Observer API
提供了一种异步检测目标元素与祖先元素或视口(可统称为根元素)相交情况变化的方法。
- 注意点:
因为该 API 是异步的,它不会随着目标元素的滚动同步触发,而
IntersectionObserver API
是通过requestIdleCallback()实现,即只有浏览器空闲下来,才会执行观察器。这意味着这个观察器的优先级非常低。
1.1 Intersection Observer API 出现的原因
因为在如今网页开发的过程中,常常需要判断某个元素是否进入了"视口"(viewport),即用户能不能看到它。
面对这种相交检测的任务时,过去我们通常会使用Element.getBoundingClientRect()
等方法来获取相关元素的位置信息,并且还会用到事件监听。
然而事件监听和调用Element.getBoundingClientRect()
等 API 都是运行在主线程,因此频繁触发、调用会造成性能问题,而且这种检测方法使用起来比较繁琐。
因此官方就提出了Intersection Observer API
,该 API 的出现就是为了高效的解决以下两大类问题:
- 某个元素是否可见,如:
- 图片懒加载——当图片滚动到可见时才进行加载
- 内容无限滚动——当用户滚动到接近底部时直接加载更多,而无需翻页,给用户一种网页可以无限滚动的错觉
- 两个元素是否相交,如:
- 检测广告的曝光情况——为了计算广告收益,需要知道广告元素的曝光情况
- 在用户看见某个区域时执行任务或播放动画
Intersection Observer API
会注册一个回调函数,只会在以下两种情况触发:
- 目标元素进入或退出根元素
- 交叉比达到阈值时,补充点:
- 但是该 API 无法提供重叠的像素个数或具体哪个像素重叠,只能设置阈值来进行控制回调函数的调用。
这样,浏览器的主线程就不用在监听元素是否相交,并且IntersectionObserver API
是异步进行检测的,也不会占用主线程的资源,从而性能上得到了提升。
1.2 Intersection observer 的重要概念
Intersection observer API 有以下五个重要的概念:
- 目标(target)元素 --- 我们要监听的元素
- 根(root)元素 --- 帮助我们判断目标元素是否符合条件的元素
以下两种情况根元素会默认为顶级文档的视口(一般为 html)。
- 目标元素不是可滚动元素的后代且不传值时
- 指定根元素为 null
- 交叉比(intersection ratio)---目标元素与根根的交集相对于目标元素百分比的表示(取值范围 0.0-1.0)。
- 阈值(threshold) --- 回调函数触发的条件。
- 回调函数(callback) --- 为该 API 配置的函数,会在设定的条件下触发。
2.IntersectionObserver()构造器
IntersectionObserver()
构造器用于创建一个 IntersectionObserver 对象,并会将该对像进行放回。
该构造器函数的配置参数如下图所示:
其语法如下:
var observer = new IntersectionObserver(callback[, options]);
2.1 IntersectionObserver()构造器的参数与返回值
首先我们先了解一下IntersectionObserver()
构造器的参数,其参数有:
-
callback(必选参数) --- 当交叉比超过指定阈值触发回调函数,此函数可接受两个参数:
entries
--- 由IntersectionObserverEntry
对象组成的数组 但每个被触发的阈值,都或多或少与指定阈值有偏差。observer
--- 返回被调用的IntersectionObserver
实例。
-
options(可选参数) --- 用于配置回调函数触发的条件,其参数下还有三个子参数:
root
--- 指定根元素。用于检查目标的可见性。默认为浏览器视口。- 如果指定为 null,也为浏览器视口。
- 必须是目标元素的父级元素。
rootMargin
--- 根元素的扩缩边距。其传值形式与 CSS 中 margin 一样,用于控制根元素每一边的扩缩(单位为 px 或%),从而控制计算根元素和目标元素的交集的区域范围,默认值为 0。threshold
--- 阈值,回调函数触发的条件。取值范围为 0.0-1.0,默认值为 0.0。- 当传入数值类型时,只会触发一次。
- 当传入数组类型时,可触发多次。
- 如:[0,0.25,0.5,0.75,1]表示目标元素在跟元素的可见程度每多 25% 就执行一次回调
-
该函数的返回值: 一个新的
IntersectionObserver
对像。- 该对象会按照设定的阈值来监听目标元素。
- 调用自身的
observe()
方法开始对目标元素进行监听。
2.2 IntersectionObserver()构造器的基本语法与异常信息
使用 IntersectionObserver()构造器创建 IntersectionObserver 对象并进行监听的语法如代码下所示:
let options = {
root: document.querySelector("#root"), //根元素
rootMargin: "0px", //传值形式类似于css的margin 传一个值则四个边都为0
threshold: 0, //触发条件 表示目标元素刚进入根元素时触发
};
//IntersectionObserver对象
let observer = new IntersectionObserver(callback, options);
let target = document.querySelector("#target"); //目标元素
observer.observe(target); //开始监听该目标元素
- 两种异常类型:
- SyntaxError --- 指定的 rootMargin 不存在或不符合语法。
- RangeError --- 一个或多个阈值超出了 0.0 到 1.0 的范围。
3.IntersectionObserver 对象
IntersectionObserver 接口(从属于Intersection Observer API
)提供了一种异步观察目标元素与根元素 交叉状态的方法。
当 IntersectionObserver 对象被创建时,就会被指定所监听的根元素、阀值等信息。一旦 IntersectionObserver 被创建后就无法更改其指定信息。
- 所以一个给定的观察者对象只能用来监听可见区域的特定变化值;当然你也可以在同一个观察者对象中配置监听多个目标元素。
该对象的属性与方法如下图所示:
3.1 IntersectionObserver 对象的属性与方法
3.1.1 三个属性
该对像的三个属性与IntersectionObserver()
构造器的 options 参数类似,并且这三个属性都只能读取操作,不能进行更改。
属性 | 说明 | 默认值 |
---|---|---|
root | 指定根元素。如果传值为 null,则为顶级文档的视窗。 | 顶级文档的视口(一般为 html) |
rootMargin | 根元素的扩缩边距。其传值形式与 CSS 中 margin 一样,用于控制根元素每一边的扩缩(单位为 px 或%),从而控制计算根元素和目标元素的交集的区域范围。单位为 px 或%。默 | "0px 0px 0px 0px" |
thresholds | 一个包含阈值的数组,并按升序排列,列表中的每个阈值都是监听对象的交叉区域与边界区域的比率。当监听对象的任何阈值被越过时,都会触发回调函数。 | 0 |
3.1.2 四个方法
该对象的四个方法如下表:
方法 | 说明 |
---|---|
observe(target) | 开始监听指定目标元素 |
unobserve(target) | 停止监听指定的目标元素 |
takeRecords() | 返回所有观察目标的 IntersectionObserverEntry 对象数组 |
disconnect() | 使 IntersectionObserver 对象停止全部监听工作 |
4. IntersectionObserverEntry 对象
IntersectionObserverEntry
接口(从属于 Intersection Observer API)描述了目标元素与其根元素容器在某一特定过渡时刻的交叉状态。
IntersectionObserverEntry
对像数组作为entries
参数传递给IntersectionObserver
对像的回调函数中; 此外,这对象数组只能通过调用IntersectionObserver.takeRecords()
来获取。
该对象的主要属性如下图所示:
4.1 IntersectionObserverEntry 对象的属性
IntersectionObserverEntry 对象的七个属性都是只读属性,如下表所示:
属性 | 说明 |
---|---|
target | 返回目标元素,表示目前该对象正监听的元素 |
isIntersecting | 返回一个布尔值,目标元素刚出现在根元素可视区时返回 true;目标元素从根元素可视区消失返回 false;以上两种情况都会触发 callback 函数 |
boundingClientRect | 返回目标元素的矩形区域的信息,返回结果与element.getBoundingClientRect()相同 |
rootBounds | 返回根元素的矩形区域的信息,getBoundingClientRect()方法的返回值,如果没有根元素(即直接相对于视口滚动),则返回 null |
intersectionRect | 返回目标元素与视口(或根元素)的交叉区域的信息 |
intersectionRatio | 返回目标元素的可见比例,即intersectionRect 占boundingClientRect 的比例,完全可见时为 1,完全不可见时小于等于 0 |
time | 返回一个记录从IntersectionObserver 的时间原点到交叉被触发的时间的时间戳 |
5. Intersection Observer API 的兼容性
该 API 的兼容性如下:
详情大家可参考CAN I USE - intersectionobserver。
6. Intersection Observer API 的简单案列
大家可以在自己电脑运行一下下面的代码,会有更深的理解。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<style>
* {
margin: 0;
padding: 0;
}
.container > div {
margin: 5px auto;
width: 100px;
height: 100px;
outline: 1px solid red;
}
</style>
</head>
<body>
<div class="container">
<div class="item">1</div>
<div class="item">2</div>
<div class="item">3</div>
<div class="item">4</div>
<div class="item">5</div>
<div class="item">6</div>
<div class="item">7</div>
<div class="item">8</div>
<div class="item">9</div>
<div class="item">10</div>
<div class="item">11</div>
<div class="item">12</div>
<div class="item">13</div>
<div class="item">14</div>
<div class="item">15</div>
</div>
<script>
//io 为 IntersectionObserver对象 - 由IntersectionObserver()构造器创建
var io = new IntersectionObserver((entries) => {
//entries 为 IntersectionObserverEntry对像数组
entries.forEach((item) => {
//item 为 IntersectionObserverEntry对像
// isIntersecting是一个Boolean值,判断目标元素当前是否可见
if (item.isIntersecting) {
//div 可见时 进行相关操作
console.log(item.target.innerText);
io.unobserve(item.target); //停止监听该div DOM节点
}
});
}); //不传options参数,默认根元素为浏览器视口
const divArr = [...document.querySelectorAll(".item")];
divArr.forEach((div) => io.observe(div)); // 遍历监听所有div DOM节点
</script>
</body>
</html>
我已在 Vue2 使用Intersection Observer API
实现了图片懒加载效果哦,大家可以去看看。Vue2 中自定义图片懒加载指令 2.0
参考博客
- MDN - Intersection Observer API
- MDN - IntersectionObserver.IntersectionObserver()
- MDN - Intersection Observer
- MDN - IntersectionObserverEntry
- 超好用的 API 之 IntersectionObserver
- 阮一峰 - IntersectionObserver API 使用教程
结语
这是我目前所了解的知识面中最好的解答,当然也有可能存在一定的误区。
所以如果对本文存在疑惑,可以在评论区留言,我会及时回复的,欢迎大家指出文中的错误观点。
最后码字不易,觉得有帮助的朋友点赞、收藏、关注走一波。
本网站是一个以CSS、JavaScript、Vue、HTML为核心的前端开发技术网站。我们致力于为广大前端开发者提供专业、全面、实用的前端开发知识和技术支持。 在本网站中,您可以学习到最新的前端开发技术,了解前端开发的最新趋势和最佳实践。我们提供丰富的教程和案例,让您可以快速掌握前端开发的核心技术和流程。 本网站还提供一系列实用的工具和插件,帮助您更加高效地进行前端开发工作。我们提供的工具和插件都经过精心设计和优化,可以帮助您节省时间和精力,提升开发效率。 除此之外,本网站还拥有一个活跃的社区,您可以在社区中与其他前端开发者交流技术、分享经验、解决问题。我们相信,社区的力量可以帮助您更好地成长和进步。 在本网站中,您可以找到您需要的一切前端开发资源,让您成为一名更加优秀的前端开发者。欢迎您加入我们的大家庭,一起探索前端开发的无限可能!代办报建
本公司承接江浙沪报建代办施工许可证。
联系人:张经理,18321657689(微信同号)。
12条评论
楼主很有艺术范!http://e8plne.blbjwmr.com
这位作者的文笔极其出色,用词精准、贴切,能够形象地传达出他的思想和情感。http://z4dq.qx5.net
不错哦,楼主这是要火的节奏啊!http://t8c.xiongmaokaoyu.com
好东西,学习学习!http://264w.yfegame-download.net
被楼主的逻辑打败了!http://nak.bjlongchao.com
怎么我回帖都没人理我呢?http://3xkv.fzxxhg.com
有品位!http://o340i.35meeting.com
坚持回帖!http://k8i9u.f0h5.com
知识就是力量啊!http://hzi.fxc1.com
知识就是力量啊!https://www.skypeis.com/
楼主就是我的榜样哦https://www.clashis.com/
支持楼上的!https://www.telegramip.com/
发表评论