高阶函数封装js动画

461 阅读2分钟

我们在生活中肯定看到过这样的场景,在我们进入页面或者刷新页面的时候数字(金额)会从高到低的一个动画效果;那么这是怎么做的呢?最开始的时候我以为是用css3来做的;后来看了别人的教程才发现,原来是用js写的;我没有完全按照教程的来,我用到的是Hz为60来计算的,教程是根据时间;大致思路是差不多的

需求分析

既然我们知道是用JS来做的,那么肯定是去变化数字了;既然我们要做到这几点,那么肯定是需要封装一些参数的

  • 时间 duration:指在此动画期间的一个事件间隔
  • from 起始值:值我们从某一个值开始动画
  • to 目标值:值这是我们最终的一个值
  • onProgress 回调函数:每次得到值以后的一个回调,便于得到数据渲染

注意:

这儿用到了window.requestAnimationFrame方法,然后在其中回调函数执行次数通常是每秒 60 次;下面代码中用到了此逻辑

代码分析

  • 将duration(毫秒)转为秒
  • 由于requestAnimationFrame有60Hz(每秒执行60次),所以将秒乘60并取整就可以得到每秒执行多少次
  • 然后dis计算出起始值和目标值差值多少
  • 差值除以每秒执行多少次,也就得到了步长
  • 在每次执行动画的时候都将得到的步长和初始值相加即可
  • 最后就是根据相对于的条件停止即可

模仿写法

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        .number {
            font-weight: 700;
            font-size: 36px;
            width: 300px;
            margin: 100px auto;
        }
    </style>
</head>

<body>
    <div class="number"></div>
    <script>
        const number = document.querySelector('.number');
        /**
         * duration:秒
         * from:来源值
         * to:目标值
         * onProgress:回调函数
         **/
        function animation(duration, from, to, onProgress) {
            var start = new Date().getTime()
            let dur = (duration) / 1000;
            let frequency = Math.floor(dur * 60); // 每次

            const dis = to - from; // 差值
            console.log(dis);
            const speed = Math.ceil(dis / frequency); // 步长
            console.log(speed);
            let value = from; // 当前的值
            let d = from - to; // 初始值
            function _run() {
                var end = new Date().getTime()
                if (d <= to) {
                    value = to;
                    onProgress(value);
                    console.log('cost is', `${end - start}ms`)
                    return;
                };
                d = d + speed; // 相减
                value = d;
                onProgress(value);
                requestAnimationFrame(_run);
            };
            requestAnimationFrame(_run);
        };

        animation(2000,2299,299,(val)=>{
            number.innerHTML = `<span style="color:red">${val}</span>`;
        })
    </script>
</body>

</html>

网上教程

效果代码:个人感觉跟我写的差不多,数字会跑很快;感觉都都看不清了;我模仿的写法也是这样。

  • 完整代码:
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        .number {
            font-weight: 700;
            font-size: 36px;
            width: 300px;
            margin: 100px auto;
        }
    </style>
</head>

<body>
    <div class="number"></div>
    <script>
        const number = document.querySelector('.number');
        
        /**
         * duration:秒
         * from:来源值
         * to:目标值
         * onProgress:回调函数
         **/
        function animation(duration, from, to, onProgress) {
            const dis = to - from; // 差值
            const speed = dis / duration; // 步长
            const startTime = Date.now();
            let value = from; // 当前的值
            onProgress(value);

            function _run() {
                const now = Date.now();
                const time = now - startTime;

                if (time >= duration) {
                    value = to;
                    onProgress(value);
                    return;
                };
                const d = Math.floor(time * speed);
                value = from + d;
                onProgress(value);
                requestAnimationFrame(_run);
            };
            requestAnimationFrame(_run);
        };

        animation(1000,1099,299,(val)=>{
            number.textContent = val.toFixed(2);
        })
    </script>
</body>

</html>

修改后的效果

增加了一个判断; 如代码所示,每次执行一次动画的时候+1,执行6次以后再进行回调展示数据,就不会展示那么频繁,从而导致数据模糊效果了。

往期文章