feat: add count-up animation for homepage statistics

This commit is contained in:
2026-02-11 14:16:07 +08:00
parent cb1490d5a2
commit e26b2c7d9c

View File

@@ -47,7 +47,7 @@
<div class="absolute inset-0 bg-gradient-to-br from-blue-500/20 to-blue-600/5 rounded-2xl blur-xl group-hover:blur-2xl transition-all duration-300"></div>
<div class="relative bg-gradient-to-br from-white to-blue-50/30 rounded-2xl p-6 border border-blue-100/50 shadow-lg group-hover:shadow-blue-500/20 group-hover:scale-[1.02] transition-all duration-300">
<div class="text-center">
<div class="text-4xl md:text-5xl lg:text-6xl font-black text-transparent bg-clip-text bg-gradient-to-r from-blue-600 to-blue-700 mb-3 group-hover:scale-110 transition-transform duration-300">700+</div>
<div class="text-4xl md:text-5xl lg:text-6xl font-black text-transparent bg-clip-text bg-gradient-to-r from-blue-600 to-blue-700 mb-3 group-hover:scale-110 transition-transform duration-300 counter" data-target="700" data-suffix="+">0+</div>
<div class="text-gray-700 text-sm md:text-base font-medium">视觉理解大模型</div>
</div>
</div>
@@ -56,7 +56,7 @@
<div class="absolute inset-0 bg-gradient-to-br from-blue-500/20 to-blue-600/5 rounded-2xl blur-xl group-hover:blur-2xl transition-all duration-300"></div>
<div class="relative bg-gradient-to-br from-white to-blue-50/30 rounded-2xl p-6 border border-blue-100/50 shadow-lg group-hover:shadow-blue-500/20 group-hover:scale-[1.02] transition-all duration-300">
<div class="text-center">
<div class="text-4xl md:text-5xl lg:text-6xl font-black text-transparent bg-clip-text bg-gradient-to-r from-blue-600 to-blue-700 mb-3 group-hover:scale-110 transition-transform duration-300">99.9%</div>
<div class="text-4xl md:text-5xl lg:text-6xl font-black text-transparent bg-clip-text bg-gradient-to-r from-blue-600 to-blue-700 mb-3 group-hover:scale-110 transition-transform duration-300 counter" data-target="99.9" data-suffix="%">0%</div>
<div class="text-gray-700 text-sm md:text-base font-medium">SLA 可用性</div>
</div>
</div>
@@ -65,7 +65,7 @@
<div class="absolute inset-0 bg-gradient-to-br from-blue-500/20 to-blue-600/5 rounded-2xl blur-xl group-hover:blur-2xl transition-all duration-300"></div>
<div class="relative bg-gradient-to-br from-white to-blue-50/30 rounded-2xl p-6 border border-blue-100/50 shadow-lg group-hover:shadow-blue-500/20 group-hover:scale-[1.02] transition-all duration-300">
<div class="text-center">
<div class="text-4xl md:text-5xl lg:text-6xl font-black text-transparent bg-clip-text bg-gradient-to-r from-blue-600 to-blue-700 mb-3 group-hover:scale-110 transition-transform duration-300">15+</div>
<div class="text-4xl md:text-5xl lg:text-6xl font-black text-transparent bg-clip-text bg-gradient-to-r from-blue-600 to-blue-700 mb-3 group-hover:scale-110 transition-transform duration-300 counter" data-target="15" data-suffix="+">0+</div>
<div class="text-gray-700 text-sm md:text-base font:medium">合作伙伴</div>
</div>
</div>
@@ -74,7 +74,7 @@
<div class="absolute inset-0 bg-gradient-to-br from-blue-500/20 to-blue-600/5 rounded-2xl blur-xl group-hover:blur-2xl transition-all duration-300"></div>
<div class="relative bg-gradient-to-br from-white to-blue-50/30 rounded-2xl p-6 border border-blue-100/50 shadow-lg group-hover:shadow-blue-500/20 group-hover:scale-[1.02] transition-all duration-300">
<div class="text-center">
<div class="text-4xl md:text-5xl lg:text-6xl font-black text-transparent bg-clip-text bg-gradient-to-r from-blue-600 to-blue-700 mb-3 group-hover:scale-110 transition-transform duration-300">40+</div>
<div class="text-4xl md:text-5xl lg:text-6xl font-black text-transparent bg-clip-text bg-gradient-to-r from-blue-600 to-blue-700 mb-3 group-hover:scale-110 transition-transform duration-300 counter" data-target="40" data-suffix="+">0+</div>
<div class="text-gray-700 text-sm md:text-base font-medium">软著专利</div>
</div>
</div>
@@ -83,3 +83,51 @@
</div>
</div>
</section>
<script>
(function() {
const counters = document.querySelectorAll('.counter');
const duration = 2000;
let animated = false;
function animateCounter(counter: Element) {
const target = parseFloat(counter.getAttribute('data-target') || '0');
const suffix = counter.getAttribute('data-suffix') || '';
const isDecimal = target % 1 !== 0;
const startTime = performance.now();
const startValue = 0;
function update(currentTime: number) {
const elapsed = currentTime - startTime;
const progress = Math.min(elapsed / duration, 1);
const easeOutQuart = 1 - Math.pow(1 - progress, 4);
const currentValue = startValue + (target - startValue) * easeOutQuart;
if (isDecimal) {
counter.textContent = currentValue.toFixed(1) + suffix;
} else {
counter.textContent = Math.floor(currentValue) + suffix;
}
if (progress < 1) {
requestAnimationFrame(update);
}
}
requestAnimationFrame(update);
}
const observer = new IntersectionObserver((entries) => {
entries.forEach((entry) => {
if (entry.isIntersecting && !animated) {
animated = true;
counters.forEach(animateCounter);
}
});
}, { threshold: 0.3 });
counters.forEach((counter) => {
observer.observe(counter);
});
})();
</script>