767931202d
- 重构 Header 导航、Footer 页脚、MobileMenu 移动端菜单 - 新增 MobileTabBar 移动端底部导航栏 - 更新 MegaDropdown 大型下拉导航 - 重构 SEO 结构化数据组件 - 更新数据层常量 (products, services, solutions, navigation 等) - 新增 useCountUp 数字递增 Hook - 修复 .gitignore 中 src/lib 被错误忽略的问题
64 lines
1.4 KiB
TypeScript
64 lines
1.4 KiB
TypeScript
'use client';
|
|
|
|
import { useState, useEffect, useRef } from 'react';
|
|
|
|
interface UseCountUpOptions {
|
|
end: number;
|
|
duration?: number;
|
|
start?: number;
|
|
decimals?: number;
|
|
easing?: (t: number) => number;
|
|
enabled?: boolean;
|
|
}
|
|
|
|
const easeOutCubic = (t: number) => 1 - Math.pow(1 - t, 3);
|
|
|
|
export function useCountUp({
|
|
end,
|
|
duration = 1800,
|
|
start = 0,
|
|
decimals = 0,
|
|
easing = easeOutCubic,
|
|
enabled = true,
|
|
}: UseCountUpOptions) {
|
|
const [value, setValue] = useState(start);
|
|
const startTimeRef = useRef<number | null>(null);
|
|
const frameRef = useRef<number>(0);
|
|
|
|
useEffect(() => {
|
|
if (!enabled) {
|
|
setValue(end);
|
|
return;
|
|
}
|
|
|
|
setValue(start);
|
|
startTimeRef.current = null;
|
|
|
|
const animate = (now: number) => {
|
|
if (startTimeRef.current === null) {
|
|
startTimeRef.current = now;
|
|
}
|
|
|
|
const progress = Math.min((now - startTimeRef.current) / duration, 1);
|
|
const eased = easing(progress);
|
|
const current = start + (end - start) * eased;
|
|
|
|
setValue(Number(current.toFixed(decimals)));
|
|
|
|
if (progress < 1) {
|
|
frameRef.current = requestAnimationFrame(animate);
|
|
} else {
|
|
setValue(end);
|
|
}
|
|
};
|
|
|
|
frameRef.current = requestAnimationFrame(animate);
|
|
|
|
return () => {
|
|
cancelAnimationFrame(frameRef.current);
|
|
};
|
|
}, [end, duration, start, decimals, easing, enabled]);
|
|
|
|
return value;
|
|
}
|