告别数字动画繁琐实现:Vue3组合式API封装countUp.js全指南

告别数字动画繁琐实现:Vue3组合式API封装countUp.js全指南

【免费下载链接】countUp.js Animates a numerical value by counting to it 【免费下载链接】countUp.js 项目地址: https://gitcode.com/gh_mirrors/co/countUp.js

你还在为实现数字滚动动画编写冗长代码吗?还在纠结如何将第三方库优雅集成到Vue3项目中吗?本文将带你用组合式API(Composition API)封装countUp.js,打造一个可复用、易维护的数字动画组件,让数值从0平滑滚动到目标值的效果实现只需3行代码。

读完本文你将获得:

  • 掌握countUp.js核心API及Vue3组合式封装技巧
  • 学会使用自定义hooks抽象动画逻辑
  • 获得一个支持12种配置项的通用数字动画组件
  • 解决滚动触发、暂停续播等常见业务场景问题

认识countUp.js:轻量级数字动画库

countUp.js是一个零依赖的数值动画库(src/countUp.ts),通过平滑计数到目标值实现动态视觉效果。其核心原理是利用requestAnimationFrame API逐帧更新数值,支持自定义动画时长、小数位数、千分位分隔符等配置。

数字动画效果

基础用法示例

// 原生JS初始化
const countUp = new CountUp('targetId', 1000, {
  duration: 2,  // 动画时长(秒)
  useGrouping: true  // 启用千分位分隔
});
countUp.start();

Vue3组合式API封装优势

相比Vue2的选项式API,组合式API在封装第三方库时有三大优势:

  • 逻辑复用:通过自定义hooks抽离动画逻辑,可在多个组件中复用
  • 类型安全:配合TypeScript获得完整类型提示(tsconfig.json
  • 响应式集成:天然适配ref/reactive数据响应系统

传统实现vs组合式封装对比

实现方式代码量复用性维护成本
选项式API80行/组件低(需mixins)
组合式API30行/hook + 10行/组件高(hooks调用)

从零开始封装组件

1. 安装与引入

通过npm安装核心依赖:

npm install countup.js --save

国内用户可使用淘宝npm镜像加速安装:

npm install countup.js --save --registry=https://registry.npmmirror.com

2. 创建组合式Hook:useCountUp

新建src/hooks/useCountUp.ts文件,封装核心动画逻辑:

import { ref, onMounted, onUnmounted, Ref } from 'vue';
import { CountUp, CountUpOptions } from 'countup.js';

export function useCountUp(
  targetRef: Ref<HTMLElement | null>,
  endVal: number,
  options?: CountUpOptions
) {
  const countUpInstance = ref<CountUp | null>(null);
  const isAnimating = ref(false);

  // 初始化实例
  const initCountUp = () => {
    if (!targetRef.value) return;
    
    countUpInstance.value = new CountUp(targetRef.value, endVal, {
      startVal: 0,
      duration: 2,
      ...options
    });
    
    // 处理初始化错误
    if (countUpInstance.value.error) {
      console.error('CountUp初始化失败:', countUpInstance.value.error);
    }
  };

  // 开始动画
  const start = () => {
    if (countUpInstance.value && !isAnimating.value) {
      countUpInstance.value.start(() => {
        isAnimating.value = false;
      });
      isAnimating.value = true;
    }
  };

  // 暂停/继续动画
  const pauseResume = () => {
    countUpInstance.value?.pauseResume();
    isAnimating.value = !isAnimating.value;
  };

  // 生命周期管理
  onMounted(initCountUp);
  onUnmounted(() => {
    countUpInstance.value?.reset();
  });

  return { start, pauseResume, isAnimating };
}

3. 开发数字动画组件

创建src/components/CountUpNumber.vue组件:

<template>
  <span ref="countRef" class="count-up-number"></span>
</template>

<script setup lang="ts">
import { ref, toRefs, defineProps } from 'vue';
import { useCountUp } from '../hooks/useCountUp';

// 定义组件Props
const props = defineProps<{
  endVal: number;
  duration?: number;
  prefix?: string;
  suffix?: string;
  decimalPlaces?: number;
  enableScrollSpy?: boolean;
}>();

const countRef = ref<HTMLElement | null>(null);
const { endVal, ...options } = toRefs(props);

// 调用组合式Hook
const { start, pauseResume, isAnimating } = useCountUp(
  countRef,
  endVal.value,
  options
);

// 暴露控制方法
defineExpose({ start, pauseResume });
</script>

4. 实现滚动触发动画

利用IntersectionObserver API增强组件,实现元素进入视口时自动开始动画:

// 在useCountUp hook中添加
import { useIntersectionObserver } from '@vueuse/core';

// ...省略原有代码

onMounted(() => {
  initCountUp();
  
  if (options.enableScrollSpy) {
    const { stop } = useIntersectionObserver(
      targetRef,
      ([{ isIntersecting }]) => {
        if (isIntersecting) {
          start();
          stop(); // 只触发一次
        }
      },
      { threshold: 0.1 } // 元素可见10%时触发
    );
    
    onUnmounted(stop);
  }
});

组件应用与配置项

基础使用示例

在页面中引入组件并传入基础参数:

<template>
  <div class="dashboard">
    <count-up-number 
      :endVal="12345" 
      :duration="3" 
      prefix="$" 
      suffix="/月"
    />
  </div>
</template>

<script setup lang="ts">
import CountUpNumber from '@/components/CountUpNumber.vue';
</script>

完整配置项说明

参数名类型默认值说明
endValnumber-目标数值
durationnumber2动画时长(秒)
startValnumber0起始数值
decimalPlacesnumber0小数位数
useGroupingbooleantrue是否启用千分位
separatorstring','千分位分隔符
prefixstring''数值前缀
suffixstring''数值后缀
enableScrollSpybooleanfalse是否滚动触发
scrollSpyDelaynumber200滚动触发延迟(ms)
onCompleteFunction-动画完成回调
onStartFunction-动画开始回调

常见问题解决方案

1. 动态更新目标值

当需要响应式更新目标值时,可通过update方法实现:

<template>
  <count-up-number ref="counter" :endVal="currentVal" />
  <button @click="updateVal">更新数值</button>
</template>

<script setup lang="ts">
import { ref } from 'vue';
const currentVal = ref(1000);
const counter = ref(null);

const updateVal = () => {
  currentVal.value = 5000;
  counter.value.update(currentVal.value);
};
</script>

2. 暂停与续播控制

利用组件暴露的方法实现动画控制:

<template>
  <div>
    <count-up-number ref="counter" :endVal="10000" />
    <button @click="toggleAnimation">
      {{ isAnimating ? '暂停' : '继续' }}
    </button>
  </div>
</template>

<script setup lang="ts">
import { ref, watch } from 'vue';
const counter = ref(null);
const isAnimating = ref(true);

const toggleAnimation = () => {
  counter.value.pauseResume();
  isAnimating.value = !isAnimating.value;
};
</script>

性能优化建议

  1. 懒加载组件:对非首屏数字使用Vue的defineAsyncComponent延迟加载
  2. 防抖动处理:滚动触发时添加200ms防抖避免频繁触发
  3. 共享实例:在大数据看板场景下,通过工厂函数共享CountUp实例
  4. CSS优化:为数字元素添加will-change: transform提升动画性能

总结与展望

通过组合式API封装的countUp.js组件,既保留了原库的强大功能,又充分发挥了Vue3的响应式优势。这种封装方式不仅实现了逻辑复用,还使代码结构更清晰、维护成本更低。

后续可扩展方向:

  • 支持自定义动画缓动函数
  • 实现数字滚动方向控制
  • 添加数字变化过渡效果

收藏本文,下次实现数字动画时直接复用组件!关注作者获取更多Vue3组合式API实战技巧。

本文示例代码已同步至项目仓库demo/demo.js,可直接运行查看效果。

【免费下载链接】countUp.js Animates a numerical value by counting to it 【免费下载链接】countUp.js 项目地址: https://gitcode.com/gh_mirrors/co/countUp.js

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值