【前端实践系列之十七】动起来!数字滚动效果组件开发实战

1,258 阅读1分钟

--- theme: smartblue

这是我参与更文挑战的第26天,活动详情查看: 更文挑战 !

👽 概论

最高端的动画效果,往往由最朴素的方法实现,直接看效果。

ps: 此次组件开发使用vue实现。

👽 实现思路

老规矩,先说实现思路:每位数字所在的列都有竖排的0~9十个数字,需要展示几就通过动态控制css将其推到相应位置。

👽 基本布局

按照如上思路,首先我们来实现竖排数字的基本布局:

<!--
 * @Author: 星始流年
 * @Description:父组件
-->
<template>
  <RollingNum  :num="num"></RollingNum>
</template>
<script>

import RollingNum from "../../components/rollingNum/rollingNum.vue";

export default {
  name: "Home",
  components: {
    RollingNum,
  },
  data() {
      num: 270,
    };
  },
};
</script>
<!--
 * @Author: 星始流年
 * @Description:数字滚动组件
-->

<template>
  <!-- 所有数字的整体容器 -->
  <div
    class="num-box"
    :style="{ fontSize, height: fontSize, lineHeight: fontSize }"
  >
    <!-- 单个数字的容器 -->
    <div
      v-for="(item, i) in splitNum"
      :key="i + 'l'"
      ref="numEL"
      class="num-item"
    >
      <!-- 所有备用数字的容器 -->
      <div v-for="eachNum in 10" :key="eachNum" class="num">
        {{ eachNum - 1 }}
      </div>
    </div>
  </div>
</template>

<script>
export default {
  props: {
    num: {
      type: Number,
      default: 0,
    },
    fontSize: {
      type: String,
      default: "1rem",
    },
  },
  computed: {
    splitNum() {
      const splitNum = this.num.toString().split("");
      return splitNum;
    },
  },
};
</script>

<style lang="less" scoped>
@import "./rollingNum.less";
</style>
//rollingNum.less
.num-box {
  border: 1px solid red;//border后期去掉
  display: flex;
  align-items: flex-start;
  justify-content: flex-start;
}

具体的排列效果如下:

image.png

👽 调整数字

可以看到,虽然子组件接收到的数字为270,但布局的展示数字都是0,接下来我们通过利用transform属性来将调整数字使其正确展示:

<!--
 * @Author: 星始流年
 * @Description:数字滚动组件
-->

<script>
export default {
//···
  data() {
    return {
      numEL: null,
    };
  },
  mounted() {
    this.numEL = this.$refs.numEL;//获取所有列数字的集合
    this.adaptNum()
  },
  methods: {
    //调整数字的方法
    adaptNum() {
      //遍历拆分后的数字[2,7,0]
      this.splitNum.forEach((num, i) => {
        //每个数字在Y方向上占10%,该位的数字是多少,就往上推多少个10%
        this.numEL[i].style.transform = `translateY(-${10 * num}%)`;
      });
    },
  },

}
</script>

image.png

👽 动态调整

这一阶段我们在父组件动态改变数字,然后在子组件进行监听,做出相应改变:

<!--
 * @Author: 星始流年
 * @Description:父组件
-->

export default {
  //···
  data() {
      num: 270,
    };
  },
  
  mounted() {
    setInterval(() => {
      this.num++;
    }, 1000);
  },
};
</script>
<!--
 * @Author: 星始流年
 * @Description:数字滚动组件
-->

<script>
export default {
  //···
  watch: {
    num() {
      //num改变时重新调整位置
      this.adaptNum();
    },
  },
</script>

1.gif

👽 动画添加

数字跳动很生硬,所以我们为其添加过渡效果:1.每位数字调整时遵循慢-快-慢的曲线,2. 位数越大的数字的滚动过程越长:

//rollingNum.less
.num-box {
  display: flex;
  align-items: flex-start;
  justify-content: flex-start;
  border-box:1px solid red;
  overflow: hidden;//隐藏不必要的数字
  .num-item {
    transition-timing-function: cubic-bezier(0.93, 0.01, 0, 1);//定一条动画曲线
  }
}

<!--
 * @Author: 星始流年
 * @Description:数字滚动组件
-->

<script>
export default {
  //···
  methods: {
    //调整数字的方法
    adaptNum() {
      this.splitNum.forEach((num, i) => {
        //每个数字在Y方向上占10%,该位的数字是多少,就往上推多少个10%
        this.numEL[i].style.transform = `translateY(-${10 * num}%)`;
        //位数越滚动过程越长
        this.numEL[i].style.transitionDuration = `${
          1 + (this.splitNum.length - i) * 0.3
        }s`;
      });
    },
  },
</script>

2.gif

👽 结语

基本的实现就是这样,respect.