Skip to content
On this page

🎠countTo

倒计时


总共:1000 当前 0

本身不难,主要是做动画思路的思路

TIP

动画本身是数字的变化,无论是 [位置的变化],[颜色的变化],[长宽的变化],[旋转角度的变化],[透明度的变化] 本质是数字的变化

所以动画的核心思想是找到 变化的规律,即 开始 + 速度 * 运行时间

速度 = 终点位置 - 开始位置 / 运行时间
运行时间 = 当前的时间 - 开始时的运行时间

vue
<template>
  <div>
    <el-button @click="start" type="primary">启动</el-button>
    <el-button @click="pause" type="danger">暂停</el-button>
    <el-button @click="restart" type="warning">重新启动</el-button>
    总共:{{ count }} 当前 {{ now }}
  </div>
</template>
<script lang="ts" setup>
import { ref } from "vue";
const count = ref(1000);
const now = ref(0);
let t = null;

// 暂停
const pause = () => {
  cancelAnimationFrame(t)
}

// 重新开始
const restart = () => {
  now.value = 0;
  start()
}

/**
 * 本质是数字的变化,数字的变化 = 开始位置 + 速度 + 运动了多长时间
 * 速度 = (结束位置 - 开始位置) / 总时间
 * 运动时长 = 现在的时间 - 开始的时间
 * @param duration 
 * @param from 
 * @param to 
 * @param onProgress 
 */
function animate(duration, from, to, onProgress) {
  let value = from;
  let speed = (to - from) / duration; 
  let startTime = Date.now();
  function _run() {
    let now = Date.now();
    const time = now - startTime; 
    if (time >= duration) {
      value = to;
      onProgress?.(value)
      return
    }
    value = from + speed * time;
    onProgress?.(value)
    t = requestAnimationFrame(_run)
  }
  _run()
}

const start = () => {
  animate(100000, now.value, count.value, (value: number) => {
    now.value = +value.toFixed(2);
  })
}

</script>