使用 Intersection Observer 实现滚动动画简介
创建交叉口观察器
交叉观察器 (IO) 可以检测元素何时进入或离开视口(或父元素)。它可以轻松地在滚动时添加动画,无需外部库。
IO 是异步的,并且比滚动监听器性能更高👍。
顺便说一句,如果你想通过视频学得更好,我强烈建议你观看Kewin Powell 的这个YouTube 教程。
这是使用交叉观察器在滚动时淡入动画的基本示例。
在这个例子中,我们通过在图像进入视口时为其添加类来实现图像在滚动时淡入淡出fadeIn
。这是 js:
const img = document.querySelector("img")
const callback = (entries, observer) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
entry.target.classList.add("fadeIn")
}
})
}
const options = {}
const myObserver = new IntersectionObserver(callback, options)
myObserver.observe(img)
很简单吧?快开始吧😁!
创建交叉口观察器
首先,我们通过调用其构造函数并向其传递一个回调函数和一个可选的选项对象来创建一个交叉点观察器。
const myObserver = new IntersectionObserver(callback, options)
选项
options
是一个具有 3 个属性的对象:
const options = {
root: null,
rootMargin: '0px',
threshold: 0
}
在我的淡入示例中,我返回了一个空对象{}
,因此将应用默认选项。(与不返回任何内容相同。)
- root:默认为
null
。即视口。可以是文档或 HTML 元素。如果 root 为null
,则默认为document
。 - rootMargin:默认 0px。定义根节点边界框两侧的偏移量。换句话说,正值会减小根节点边界框,负值会增大根节点边界框。尝试滚动此示例中的 3 个边界框。
类似于 CSS 的边距语法:“0px 5px 10px 15px”表示上:0px,右:5px,下:10px,左:0px。仅接受 px 和 %。⚠ 0 不是可接受的值,请使用 0px 或 0% 代替。
- 阈值:默认值为 0。阈值是介于 0 到 1.0 之间的数字。0 表示只要有一个像素可见,就会运行回调函数。1.0 表示在调用回调函数之前,每个像素都必须可见。(⚠ 如果将阈值设置为 1,并且元素大于根元素,则阈值不会达到 1,因为总有一些部分是不可见的。)
回调
回调函数以条目列表和交叉点观察器作为参数。
const callback = (entries, observer) => {
entries.forEach(entry => {
// Each entry describes an intersection change for one observed
// target element:
// entry.boundingClientRect
// entry.intersectionRatio
// entry.intersectionRect
// entry.isIntersecting
// entry.rootBounds
// entry.target
// entry.time
});
};
观察者可以用来动态地添加或移除要观察的元素。更多内容见下文。
重点在于条目列表。每个观察到的元素都有一个条目对象。通常的做法是使用它forEach
来进行迭代。
每个条目均具有以下有用的属性:
entry.isIntersecting
返回布尔值。True 表示元素当前与根元素相交。entry.target
返回观察到的元素。
我在淡入动画中都使用了它们:
const callback = (entries, observer) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
entry.target.classList.add("fadeIn")
}
})
}
entry.boundingClientRect
返回观察元素的边界矩形。entry.intersectionRatio
返回一个介于 0.0 和 1.0 之间的数字,表示观察到的元素中有多少在根中实际上是可见的。
等等。😁 我已经列出了最重要的几个。您可以在这里找到所有入口属性的列表。
选择要观察的元素
为了选择要观察的元素,我们使用了Intersection Observer 的observe()方法。
myObserver.observe(img)
就是这样!现在myObserver
将检测何时img
进入或离开视口并触发回调。
如果要观察许多元素,则必须逐一添加它们。
myObserver.observe(img1)
myObserver.observe(img2)
myObserver.observe(img3)
或者给他们一个共同的类并用以下方式迭代forEach
:
const imgList = document.querySelectorAll(".imgToAnimate")
// setting your observer here
imgList.forEach(img => {
myObserver.observe(img)
})
要停止观察,请unobserve()
调用该元素:
myObserver.unobserve(img)
要停止同时观察每个元素,请调用disconnect()
:
myObserver.disconnect()
您还可以在回调中使用这些方法:
const callback = (entries, observer) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
entry.target.classList.add("fadeIn")
// stop observing this element
observer.unobserve(entry.target)
}
})
}
编辑:在我们玩完一个元素后取消观察它是一个很好的做法。
就是这样!
我希望你喜欢这个关于 Intersection Observer 的简短介绍😃。
来源:MDN
除了滚动动画之外,它还可以用于通过脚本和媒体的延迟加载来提高渲染速度和首次内容绘制。
超越基础
这里有一些使用 IO 实现滚动动画的例子。等我有空的时候会尽量把每个例子都写一篇博客 😅。