携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第3天,点击查看活动详情
今天我们来实现一个酷炫的滚动动画,效果就是滚动的时候,序号为奇数的元素从右边进入,而偶数的元素则从左边进入,如下图所示:
那么这样一个效果要怎么实现呢?
思路分析
既然是滚动动画,那肯定涉及到滚动事件的监听,我们可以设置一个滚动边界,当元素超过这个边界的时候,就给元素添加上一个show类名,再给show类名写一些样式,而离开这个边界的时候,则将show类名移除,从而实现一个滚动动画的效果,这也就是整个动画的核心所在了,那么接下来就开始写吧!
实现
首先把结构确定一下,我们需要一些元素作为内容从而可以进行滚动
<div class="content-container">
<div class="content">Hello</div>
<div class="content">Juejin</div>
<div class="content">Plasticine</div>
<div class="content">Vue</div>
<div class="content">React</div>
<div class="content">JavaScript</div>
<div class="content">TypeScript</div>
<div class="content">Hello</div>
<div class="content">Juejin</div>
<div class="content">Plasticine</div>
<div class="content">Vue</div>
<div class="content">React</div>
<div class="content">JavaScript</div>
<div class="content">TypeScript</div>
</div>
然后再编写一下基础的样式
.content-container {
display: flex;
flex-direction: column;
place-items: center;
gap: 30px;
}
.content {
display: grid;
place-items: center;
position: relative;
width: 300px;
height: 150px;
background-color: #24283b;
border-radius: 12px;
border: 3px solid rgba(255, 255, 255, 0.8);
font-size: 24px;
transform: translateX(400%);
transition: transform 0.4s ease;
}
.content:nth-of-type(even) {
transform: translateX(-400%);
}
.content.show {
transform: translateX(0);
}
样式部分的核心就在于.content:nth-of-type(even)这个选择器,我们来看看mdn对nth-of-type这个伪类选择器的介绍:
:nth-of-type()这个CSS 伪类是针对具有一组兄弟节点的标签,用 n 来筛选出在一组兄弟节点的位置。
.content全都是兄弟元素,所以可以通过nth-of-type(even)选择出所有.content中序号为偶数的元素,让它们初始的时候向左偏移至视口之外,而默认让所有元素偏移至视口右侧,伪类选择器选择的偶数元素会覆盖默认的transform
也就是说,现在我们的元素是全都不在视口内的,奇数元素在右侧,偶数元素在左侧
然后再通过.content.show将元素归位,这样一来只需要通过js控制show类名的添加和移除来实现动画效果,这也是各司其职原则的一种体现,css就专注于样式和动画,而js则控制类名,负责逻辑相关部分
那么接下来再看看js部分应当如何实现:
((doc) => {
const oContentList = doc.querySelectorAll(".content");
const init = () => {
// 初始的时候就需要执行一次 checkContent 用于显示开始时的元素
checkContent();
bindEvent();
};
/**
* @description 检查 content 的上边界是否到达触发边界 到达的时候就添加
* show 类名 未到达则移除 show 类名
*/
const checkContent = () => {
// 取视口高度的 4 / 5 作为触发边界
const triggerBottom = window.innerHeight * (4 / 5);
oContentList.forEach((oContent) => {
// 获取盒子的上边界 用于和 triggerBottom 进行比较
const contentTop = oContent.getBoundingClientRect().top;
if (contentTop < triggerBottom) {
oContent.classList.add("show");
} else {
oContent.classList.remove("show");
}
});
};
const bindEvent = () => {
window.addEventListener("scroll", handleScroll);
};
const handleScroll = checkContent;
init();
})(document);
关键就在checkContent函数的实现,首先定义一个触发边界,我定义的触发边界是视口高度的4/5,也就是说当滚动的时候,如果元素顶部小于触发边界,则会添加show类名,这就体现为我们向下滚动时,元素逐渐上移到合适位置然后从两侧移动进入中间
而元素顶部的位置大于触发边界时,将它们移回视口两侧,最终实现了滚动动画的效果,怎么样,是不是很简单呢?😊