使用 IntersectionObserver 在 Javascript 中实现滚动动画
在您的作品集网站中使用动画是吸引用户注意力并让他们停留在您的网站上更长时间的好方法。
在本文中,我将向您展示如何在您的网站中添加一种特殊类型的 JavaScript 滚动动画,该动画会在您向下/向上滚动时激活。这将使用名为“交叉点观察器”的功能进行编码。以下是最终动画的快速预览:
YouTube 上也有关于此内容的视频:
步骤 1] 首先,让我们布局 HTML 标记和样式,以创建基本的卡片 UI
<!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>
<link rel='stylesheet' type='text/css' href='./style.css'>
</head>
<body>
<div class="wrapper">
<div class="card">
<div class="image"></div>
<h2>Profile picture</h2>
<p>Some text goes here. Some text goes here.Some text goes here.Some text goes here....</p>
</div>
</div>
</body>
<html>
style.css 如下所示:
.wrapper {
min-height: 100vh;
display: flex;
align-items: center;
justify-content: space-around;
background-color: #5dafb8;
color:white;
font-family: Verdana, Geneva, Tahoma, sans-serif;
}
.card {
height: 50vh;
border-radius: 13px;
box-shadow: 20px 40px 33px rgba(0,0,0,0.3);
padding: 2rem;
width: 35vh;
background-color: #6cc2ce;
}
/* Style a div with gradient as Background image */
.image {
width: 35vh;
height: 20vh;
background-image: linear-gradient(70deg, RoyalBlue , DarkTurquoise );
background-size: cover;
background-position: center center;
box-shadow: 10px 15px 15px 6px #3891b4;
border-radius: 15px;
}
在这个例子中,我将背景图像设置为渐变:,您可以在这里为您的项目设置一个真实的图像。所以它看起来像这样:
background-image: linear-gradient(70deg, RoyalBlue , DarkTurquoise );
步骤 2]现在让我们用关键帧动画在 CSS 中添加一些基本动画
首先,我们将添加带有关键帧动画的基本 CSS 动画。首先,我们来定位标题(h2 标签)和内容文本(p 标签):
.card h2 {
/* Animate Heading, fades in from left to right */
animation: animTitle 2s infinite;
}
.card p {
/* Animate Paragraph, fades in from right to left */
animation: animContent 2s infinite;
}
@keyframes animTitle {
from {
/* Add starting values for animation */
transform: translateX(-50px);
opacity: 0;
}
to {
/* Add Ending values for animation */
transform: translateX(0);
opacity: 1;
}
}
@keyframes animContent {
from {
/* Add starting values for animation */
transform: translateX(50px);
opacity: 0;
}
to {
/* Add Ending values for animation */
transform: translateX(0);
opacity: 1;
}
}
从上面可以看到,我们有两个关键帧动画函数,它们是在 CSS 选择器规则中调用的。它们都运行 2 秒并无限循环。这些是元素水平 x 值上的简单过渡/平移。
@keyframes animTitle {...} and @keyframes animContent { ...}
.card h2 {animation: animContent 2s infinite;} and .card p{animation: animContent 2s infinite;}
我们还将为图像添加一个特殊的弹性拉伸动画。其 CSS 规则和动画关键帧函数如下:
.card .image {
/* Animate image */
animation: animImage 2s infinite;
}
@keyframes animImage {
0% {
-webkit-transform: scale3d(1, 1, 1);
transform: scale3d(1, 1, 1);
}
30% {
-webkit-transform: scale3d(1.25, 0.75, 1);
transform: scale3d(1.25, 0.75, 1);
}
40% {
-webkit-transform: scale3d(0.75, 1.25, 1);
transform: scale3d(0.75, 1.25, 1);
}
50% {
-webkit-transform: scale3d(1.15, 0.85, 1);
transform: scale3d(1.15, 0.85, 1);
}
65% {
-webkit-transform: scale3d(0.95, 1.05, 1);
transform: scale3d(0.95, 1.05, 1);
}
75% {
-webkit-transform: scale3d(1.05, 0.95, 1);
transform: scale3d(1.05, 0.95, 1);
}
100% {
-webkit-transform: scale3d(1, 1, 1);
transform: scale3d(1, 1, 1);
}
}
我使用名为 Animista 的在线动画生成器创建了这个动画。你也可以去那里尝试其他动画。该网站会生成关键帧代码,你可以将其附加到你想要动画的容器上。就像我上面做的那样(我还重命名了关键帧函数)。
我们目前拥有的
到目前为止,我们所有的动画都是由 CSS 控制的,为了实现滚动动画,我们还需要尝试一些 JavaScript。我们还需要重新组织/修改一些 CSS 规则和 HTML 元素。这就是我们接下来要做的。
步骤 3] 在添加 IntersectionObserver 之前修改 HTML 标记
通过 JavaScript 激活动画时,我们遇到的一个关键问题是获取动画关键帧函数名称以及需要应用的规则。在我们的演示中,我们通过以下 CSS 规则实现了这一点:```css
.card h2 {
/* 动画标题,从左到右淡入 */
animation: animTitle 2s infinite;
}
.card p {
/* 动画段落,从右到左淡入 */
animation: animContent 2s infinite;
}
.card .image {
/* 动画图像 */
animation: animImage 2s infinite;
}
To apply this dynamically in javascript, we will need to abandon these css rules and use htmls data attribute to store the animation values shown above. We are also going to attach a class called "animate" to the three elements that we are going to animte. So the HTML markup for the card will look like:
```html
<div class="wrapper">
<div class="card">
<div class="image animate" data-animate="animImage 2s"></div>
<h2 class="animate" data-animate="animTitle 2s ">Profile picture</h2>
<p class="animate" data-animate="animContent 2s ">Some text goes here.Some text goes here....</p>
</div>
</div>
因此,这里最重要的部分是数据属性,例如,图片容器的数据属性是:,这里我们创建了一个名为 animate 的数据项(这是破折号后的后缀),并将其值设置为我们之前在 CSS 样式表中定义的动画设置。如果您对此感到有些奇怪,可以点击此处了解更多关于使用数据属性的信息。
data-animate="animImage 2s"
我们还需要添加更多内容,以便我们可以滚动来激活我们的动画,所以我将复制另外三个卡片包装器:
<div class="wrapper">
<div class="card">
<div class="image animate" data-animate="animImage 2s"></div>
<h2 class="animate" data-animate="animTitle 2s ">Profile picture</h2>
<p class="animate" data-animate="animContent 2s ">Some text goes here.Some text goes here....</p>
</div>
</div>
<div class="wrapper">
<div class="card">
<div class="image animate" data-animate="animImage 2s "></div>
<h2 class="animate" data-animate="animTitle 2s ">Profile picture</h2>
<p class="animate" data-animate="animContent 2s ">Some text goes here....Some text goes here....Some text goes here....Some text goes here....</p>
</div>
</div>
<div class="wrapper">
<div class="card">
<div class="image animate" data-animate="animImage 2s "></div>
<h2 class="animate" data-animate="animTitle 2s ">Profile picture</h2>
<p class="animate" data-animate="animContent 2s ">Some text goes here....Some text goes here....Some text goes here....Some text goes here....</p>
</div>
</div>
<div class="wrapper">
<div class="card">
<div class="image animate" data-animate="animImage 2s "></div>
<h2 class="animate" data-animate="animTitle 2s ">Profile picture</h2>
<p class="animate" data-animate="animContent 2s ">Some text goes here....Some text goes here....Some text goes here....Some text goes here....</p>
</div>
</div>
步骤 4] 添加 Javascript 的交叉观察器功能来检测滚动位置
交叉口观察器基本上会观察您告诉它的元素。它将观察目标元素与祖先元素相交处的变化。我们的祖先元素将是浏览器视口,我们观察到的交集目标元素是卡片的三个元素,即 .image、p 标签和 h2 标签。
您可以在此处阅读有关 Intersection Observer API 的更多信息。请注意,在 API 文档中,他们有定义根元素的示例,对于我们的情况,我将其省略,因为我希望它默认为浏览器视口(如果您没有定义根元素,它将假定祖先为根)。所以我们用例的基本代码结构将如下所示:
<script>
const callback = (entries) => {
//4] Callback code goes here
}
//1]Create a new intersectionObserver object,
//which will accept a callback function as
//a parameter.
let observer = new IntersectionObserver(callback);
//2]Select all elements that have ".animate"
//class.In our case we have three
//elements (.image,<p> and h<2>).
const animationItems = document.querySelectorAll('.animate');
//3]Loop through selected elements and add to the
//observer watch list.
animationItems.forEach(item => {
observer.observe(item)
})
</script>
Will 会在标记中内联添加此代码,位于 body 标签的末尾。为了简化操作,您需要执行 4 个步骤
1] 创建一个 IntersectionObserver 对象
2] 查询并选择需要观察的项目
3] 将选定的项目添加到 IntersectionObserver 对象的观察列表中
4] 提供一个回调函数,该函数会在每次发生交叉事件时执行某些操作。在本例中,我们希望它附加一个关键帧动画。
上面的代码中我没有写回调函数的代码。所以这是我们的下一个任务。
步骤5] IntersectionObserver回调函数
const callback = (entries) => {
// The entries variable will contain the list of
// elements that you are observing. When ever
// intersection occurs, you need to do forEach loop
// to find which one intersected.
// For this we check a flag on the element called "isIntersecting"
entries.forEach(
(entry) => {
if (entry.isIntersecting) {
console.log("The element is intersecting >");
//If intersecting then attach keyframe animation.
//We do this by assigning the data attribute
//we coded in the markup to the style.animation
//of the element
entry.target.style.animation =
entry.target.dataset.animate;
} else {
//We take of the animation if not in view
entry.target.style.animation="none";
}
}
);
}
每当发生相交时,都会调用回调函数。回调函数可以访问观察者列表中的所有元素。在回调函数中,我们必须循环查找相交的元素。我们通过检查元素上名为isIntersecting的标志来实现这一点。如果你检查 IF 语句,就会看到这样的代码:```
if (entry.isIntersecting) {...}
If it is intersecting then we attach the keyframe animation to the element, thats what the following line does :
entry.target.style.animation = entry.target.dataset.animate
Here we set the elements style.animation to the fetched data attribute called "data-animate" which was setup in step 3. For example, for the image we would get the string part off the data attribute on the elements markup:
在这种情况下,它是“animImage 2s”。
代码的 ELSE 部分删除动画,因为它不相交:` entry.target.style.animation="none"; `
因此,如果您来回滚动,动画将再次运行。
最终产品
希望你喜欢本教程,你可以在 codepen 上看到最终的代码
文章来源:https://dev.to/keefdrive/animate-on-scroll-using-intersectionobserver-5dg1