You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何修改JavaScript数字递增动画的步长

实现数字递增动画的自定义步长需求

问题描述

我正在研究一个JavaScript数字递增动画示例,希望修改计数动作的步长——即按2、3、5等数值递增,而非每次加1。目前尝试修改了frame变量的值,以及调整totalFrames和progress相关数值,但都无法实现不同步长,求实现方法。

原代码如下:

HTML代码

<button onclick="runAnimations()">Animate</button>
<ul>
  <li><span class="countup">45</span></li>
  <li><span class="countup">110</span></li>
  <li><span class="countup">53210</span></li>
</ul>

JavaScript代码

// How long you want the animation to take, in ms
const animationDuration = 10000;
// Calculate how long each ‘frame’ should last if we want to update the animation 60 times per second
const frameDuration = 1000 / 60;
// Use that to calculate how many frames we need to complete the animation
const totalFrames = (Math.round( animationDuration / frameDuration ) + 5);
// An ease-out function that slows the count as it progresses
const easeOutQuad = t => t * ( 2 - t );

// The animation function, which takes an Element
const animateCountUp = el => {
    let frame = 0;
    const countTo = parseInt( el.innerHTML, 10 );
    // Start the animation running 60 times per second
    const counter = setInterval( () => {
        frame++;
        // Calculate our progress as a value between 0 and 1
        // Pass that value to our easing function to get our
        // progress on a curve
        const progress = easeOutQuad( frame / totalFrames );
        // Use the progress value to calculate the current count
        const currentCount = Math.round( countTo * progress );

        // If the current count has changed, update the element
        if ( parseInt( el.innerHTML, 10 ) !== currentCount ) {
            el.innerHTML = currentCount;
        }

        // If we’ve reached our last frame, stop the animation
        if ( frame === totalFrames ) {
            clearInterval( counter );
        }
    }, frameDuration );
};

// Run the animation on all elements with a class of ‘countup’
const runAnimations = () => {
    const countupEls = document.querySelectorAll( '.countup' );
    countupEls.forEach( animateCountUp );
};

解决方案

原代码逻辑是通过进度比例直接计算当前数值,并非按步长累加,所以修改frame等参数无法实现步长控制。我们需要调整逻辑,基于步长计算每帧的显示值,同时保留缓动效果:

  1. 为每个计数元素添加自定义步长(通过data-step属性),也可设置全局默认步长
  2. 计算总整数步数与最后一步的余数,避免最终值偏差
  3. 利用缓动后的进度值,计算当前完成的步数,再乘以步长得到当前显示值,最后处理收尾余数

修改后的完整代码

HTML(添加data-step自定义步长)

<button onclick="runAnimations()">Animate</button>
<ul>
  <li><span class="countup" data-step="3">45</span></li>
  <li><span class="countup" data-step="5">110</span></li>
  <li><span class="countup" data-step="100">53210</span></li>
</ul>

JavaScript

const animationDuration = 10000;
const frameDuration = 1000 / 60;
const totalFrames = Math.round(animationDuration / frameDuration) + 5;
const easeOutQuad = t => t * (2 - t);

const animateCountUp = el => {
    let frame = 0;
    const countTo = parseInt(el.innerHTML, 10);
    // 获取元素自定义步长,默认步长为1
    const step = parseInt(el.dataset.step || 1, 10);
    // 计算总整数步数和最后一步的余数
    const totalFullSteps = Math.floor(countTo / step);
    const remainder = countTo % step;

    const counter = setInterval(() => {
        frame++;
        const progress = easeOutQuad(frame / totalFrames);
        
        // 根据进度计算当前完成的步数
        const currentSteps = Math.round(totalFullSteps * progress);
        // 当前显示值 = 已完成步数 * 步长
        let currentCount = currentSteps * step;

        // 动画最后一帧补全余数,确保最终值准确
        if (frame === totalFrames) {
            currentCount = countTo;
        }

        if (parseInt(el.innerHTML, 10) !== currentCount) {
            el.innerHTML = currentCount;
        }

        if (frame === totalFrames) {
            clearInterval(counter);
        }
    }, frameDuration);
};

const runAnimations = () => {
    const countupEls = document.querySelectorAll('.countup');
    countupEls.forEach(animateCountUp);
};

说明

  • 每个.countup元素可通过data-step属性设置专属步长,未设置的元素默认按步长1递增
  • 保留原有的缓动效果,动画后期会自然减速
  • 最后一帧强制设置为目标值,避免因取整导致的最终值偏差

内容的提问来源于stack exchange,提问作者Jon

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.15 04:01:15