Skip to content
本页目录

数字无限滚动组件

效果

代码

vue
<template>
  <div
    class="num-scroll__wrapper"
    :style="{
      height: blockHeight + 'px',
    }"
  >
    <div class="num-scroll__content" ref="translateDom">
      <div v-for="(item, index) in numData" :key="index">
        {{ item }}
      </div>
      <div v-for="(item, index) in numData" :key="index + '_'">
        {{ item }}
      </div>
    </div>
  </div>
</template>

<script>
import anime from "animejs";
export default {
  data() {
    let numData = new Array(10).fill("").map((item, index) => index);
    return {
      numData: numData,
      curValue: 0,
      curPostion: 0, // 当前内容位移距离
      animeInstance: null,
    };
  },
  props: {
    value: {
      type: Number,
      default: 0,
    },
    blockHeight: {
      type: Number,
      default: 30,
    },
    duration: {
      type: Number,
      default: 1000,
    },
  },
  watch: {
    value: "run",
  },
  methods: {
    run() {
      let animeDom = this.$refs.translateDom;
      if (!animeDom) return;
      //   需要位移到的位置
      let translateY = -this.value * this.blockHeight;
      // 两种情况,一种是需要位移的值在当前值的上方,也就是需要往下滚动触发无限滚动逻辑
      // 第二种就是当前位移位置在需要移动到的位置的下方,也需要无限滚动
      if (this.value < this.curValue || translateY > this.curPostion) {
        const groupSize = 10;
        translateY = -this.blockHeight * (groupSize + this.value);
      }
      this.animeInstance && this.animeInstance.pause();
      this.animeInstance = anime({
        targets: animeDom,
        translateY,
        easing: "linear",
        duration: this.duration,
        update: (anim) => {
          let curTranslateY = anim.animations.find(
            (item) => item.property === "translateY"
          );
          if (!curTranslateY) return;
          this.curPostion = parseFloat(curTranslateY.currentValue);
        },
        complete: () => {
          this.curValue = this.value;
          this.animeInstance = null;
          this.resetPos();
        },
      });
    },
    resetPos() {
      let animeDom = this.$refs.translateDom;
      anime({
        targets: animeDom,
        translateY: -this.value * this.blockHeight,
        duration: 0,
        complete: () => {
          this.curPostion = -this.value * this.blockHeight;
        },
      });
    },
  },
  mounted() {
    this.run();
  },
};
</script>
<style scoped>
.num-scroll__wrapper {
  display: inline-block;
  text-align: center;
  overflow: hidden;
  background: #000;
  color: #fff;
  font-size: 16px;
  font-weight: bold;
  width: 24px;
  border-radius: 4px;
  height: 30px;
  line-height: 30px;
  position: fixed;
  left: 50%;
  top: 50%;
}
</style>

参考