gsap实现数字滚动

js yekong

数据可视化大屏 项目开发中,需要实现数字滚动效果,这里我们使用 gsap 来封装成一个vue组件实现我们想要的效果。

gsap实现数字滚动

动画效果

使用组件

<numcard :number="item.value" :delay="index*0.15+'s'"></numcard>

组件代码

首先接收一个数字传值,然后接收数字滚动执行时间。

<template>
  <div v-if="show" class="numcard numcardItem1">
    <span class="real-time-num" ref="number">{{ currentNumber }}</span>
  </div>
</template>

<script>
import {gsap} from 'gsap';

export default {
  data() {
    return {
      currentNumber: 0,
      show: true,
    };
  },
  props: {
    number: {
      type: [Number, String],
      default() {
        return 0;
      },
    },
// :delay="0.15+'s'"
    delay: {
      type: [Number, String],
      default() {
        return 0;
      },
    },
  },
  watch: {
    number(newVal) {
      if (this.show) {
        this.$nextTick(() => {
          this.currentNumber = 0
          this.animateNumber(this.currentNumber, newVal);
        });
      }
    },
    show() {
      this.$nextTick(() => {
        this.currentNumber = 0
        this.animateNumber(this.currentNumber, this.number);
      });
    },
  },
  methods: {
    animateNumber(start, end) {
      gsap.to(this, {
        currentNumber: end,
        duration: 2,
        delay: parseFloat(this.delay),  // 添加这一行
        roundProps: 'currentNumber',
        ease: 'power1.out',
        onUpdate: () => {
          this.currentNumber = Math.round(this.currentNumber);
        },
      });
    },
  },
  mounted() {
    if (this.show) {
      this.currentNumber = 0
      this.animateNumber(this.currentNumber, this.number);
    }
  },
};
</script>

<style lang="scss">
.numcardItem1 {
  .real-time-num {
    width: auto !important;
    font-size: 22px;
    font-family: DIN-Bold;
    font-weight: bold;
    font-style: normal;
    color: #11FFFE;
    animation: slideUp 1s forwards;
  }
}

@keyframes slideUp {
  from {
    transform: translateY(100%);
    opacity: 0;
  }
  to {
    transform: translateY(0);
    opacity: 1;
  }
}
</style>

增加千分位逗号

数字滚动效果有了,不过在实际大屏项目中,我们还需要在千分位上显示逗号,如下图:

增加千分位逗号

代码调整

<template>
  <div v-if="show" class="numcard numcardItem1">
    <span class="real-time-num" ref="number">{{ formattedNumber }}</span>
  </div>
</template>

<script>
import { gsap } from 'gsap';

export default {
  data() {
    return {
      rawNumber: 0, // 更改为rawNumber,存储实际数字值
      show: true,
      showComma: false, // 是否显示千分位逗号
    };
  },
  props: {
    number: {
      type: [Number, String],
      default() {
        return 0;
      },
    },
    comma: { // 通过props控制是否显示千分位
      type: Boolean,
      default: false
    },
    delay: {
      type: [Number, String],
      default() {
        return 0;
      },
    },
  },
  computed: {
    formattedNumber() {
      if (this.showComma) {
        return this.rawNumber.toLocaleString(); // 格式化数字为千分位格式
      }
      return this.rawNumber;
    },
    currentNumber: {
      get() {
        return this.rawNumber;
      },
      set(value) {
        this.rawNumber = value;
      }
    }
  },
  watch: {
    number(newVal) {
      if (this.show) {
        this.$nextTick(() => {
          this.currentNumber = 0
          this.animateNumber(this.currentNumber, newVal);
        });
      }
    },
    show() {
      this.$nextTick(() => {
        this.currentNumber = 0
        this.animateNumber(this.currentNumber, this.number);
      });
    },
    comma(newVal) {
      this.showComma = newVal; // 设置是否显示千分位
    }
  },
  methods: {
    animateNumber(start, end) {
      gsap.to(this, {
        currentNumber: end,
        duration: 2,
        delay: parseFloat(this.delay),
        roundProps: 'currentNumber',
        ease: 'power1.out',
        onUpdate: () => {
          this.currentNumber = Math.round(this.currentNumber);
        },
      });
    },
  },
  mounted() {
    this.showComma = this.comma; // 初始化时根据props设置是否显示千分位
    if (this.show) {
      this.currentNumber = 0
      this.animateNumber(this.currentNumber, this.number);
    }
  },
};
</script>
<gsapNum :number="12345" :comma="true"/>

传入什么数字就渲染什么数字

如果有小数就渲染小数,没有小数就不渲染

<template>
  <div v-if="show" class="numcard numcardItem1">
    <span class="real-time-num gsapNum" ref="number">{{ formattedNumber }}{{unit}}</span>
  </div>
</template>

<script>
import gsap from 'gsap';

export default {
  data() {
    return {
      rawNumber: 0, // 更改为rawNumber,存储实际数字值
      show: true,
      showComma: false, // 是否显示千分位逗号
    };
  },
  props: {
    number: {
      type: [Number, String],
      default() {
        return 0;
      },
    },
    unit: { // 控制单位显示
      type: String,
      default: ''
    },
    comma: { // 通过props控制是否显示千分位
      type: Boolean,
      default: false
    },
    delay: {
      type: [Number, String],
      default() {
        return 0;
      },
    },
  },
  computed: {
    formattedNumber() {
      return this.rawNumber;
    },
    currentNumber: {
      get() {
        return this.rawNumber;
      },
      set(value) {
        this.rawNumber = value;
      }
    }
  },
  watch: {
    number(newVal) {
      if (this.show) {
        this.$nextTick(() => {
          this.currentNumber = 0
          this.animateNumber(this.currentNumber, newVal);
        });
      }
    },
    show() {
      this.$nextTick(() => {
        this.currentNumber = 0
        this.animateNumber(this.currentNumber, this.number);
      });
    },
    comma(newVal) {
      this.showComma = newVal; // 设置是否显示千分位
    }
  },
  methods: {
    animateNumber(start, end) {
      // 计算原始数字的小数位数
      let decimalPlaces = (end.toString().split('.')[1] || '').length;

      gsap.to(this, {
        currentNumber: end,
        duration: 2,
        delay: parseFloat(this.delay),
        ease: 'power1.out',
        onUpdate: () => {
          // 保持相同的小数位数
          this.currentNumber = parseFloat(this.currentNumber.toFixed(decimalPlaces));
        },
      });
    },
  },
  mounted() {
    this.showComma = this.comma;
    this.showDecimal = this.decimal; // 初始化显示小数的设置
    if (this.show) {
      this.currentNumber = 0
      this.animateNumber(this.currentNumber, this.number);
    }
  },
};
</script>

<style lang="less">
.numcardItem1 {
  .real-time-num {
    width: auto !important;
    font-size: 36px;
    font-family: DIN-Bold, DIN;
    font-weight: bold;
    color: #FDBA51;
    font-style: normal;
  }
}

@keyframes slideUp {
  from {
    transform: translateY(100%);
    opacity: 0;
  }
  to {
    transform: translateY(0);
    opacity: 1;
  }
}
</style>

更多gsap动画效果汇总

gsap动画效果汇总

喜欢