「原生练手」😊打造酷炫滚动动画

814 阅读3分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第3天,点击查看活动详情

今天我们来实现一个酷炫的滚动动画,效果就是滚动的时候,序号为奇数的元素从右边进入,而偶数的元素则从左边进入,如下图所示:

scroll animation.gif

那么这样一个效果要怎么实现呢?

思路分析

既然是滚动动画,那肯定涉及到滚动事件的监听,我们可以设置一个滚动边界,当元素超过这个边界的时候,就给元素添加上一个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)这个选择器,我们来看看mdnnth-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类名,这就体现为我们向下滚动时,元素逐渐上移到合适位置然后从两侧移动进入中间

而元素顶部的位置大于触发边界时,将它们移回视口两侧,最终实现了滚动动画的效果,怎么样,是不是很简单呢?😊