基于Vue3自定义指令,实现数字递增动画效果的v-increase
需求描述
实现一个高性能的数字递增的动画效果,为了方便以后复用,通过自定义指令跟requestAnimationFrame进行封装。
效果演示
https://codepen.io/SuperMelon/pen/ZEMaZQo
代码实现
import { Directive } from "vue";
// 动画持续时间,ms
const DURATION = 1500;
/**
* @description 基于Vue3自定义指令,实现数字递增动画效果
*
* @example `<div v-increase="100"></div>`
*/
export const increase: Directive = {
// 在绑定元素的父组件
// 及他自己的所有子节点都挂载完成后调用
mounted(el, binding) {
const { value: maxCount } = binding;
el.$animation = animate((progress) => {
el.innerText = Math.floor(maxCount * progress);
}, DURATION);
},
// 绑定元素的父组件卸载后调用
unmounted(el) {
el.$animation.cancel();
},
};
/**
* @description 基于requestAnimationFrame,实现在持续时间内执行动画的方法
*
* @param fn 动画执行函数,参数progress表示完成的进度
* @param duration 动画持续时间
* @returns {object.cancel} 取消动画
*/
export const animate = function (
fn: (progress: number) => void,
duration: number
) {
const animate = () => {
animation = requestAnimationFrame(animate);
const now = new Date().getTime();
const progress = Math.floor(((now - START) / duration) * 100) / 100;
fn(progress > 1 ? 1 : progress);
// 到达持续时间,结束动画
if (now - START > duration) {
cancel();
}
};
const cancel = () => {
cancelAnimationFrame(animation);
};
const START = new Date().getTime();
let animation = requestAnimationFrame(animate);
return {
cancel: () => {
cancelAnimationFrame(animation);
},
};
};