JavaScript基于时间的动画算法,前端开发学习方法【附源码】_mb6130d15434330

通过查找资料发现,基于帧的算法(Frame-based)来实现动画会导致不同帧率的平台体验不一致,而基于时间(Time-based)的动画算法可以很好地改良这种情况,让不同帧率的情况下都能达到较为统一的速度上的体验。

本文介绍的就是基于帧动画算法和基于时间动画算法的差异,以及对基于时间算法的改良。

基于帧的动画算法(Frame-based)


相信做过前端的人对使用JavaScript实现动画的原理都很熟悉。现在让你实现一个让一个div从左到右来回移动的JS代码,你可能嗖嗖就写出来了:

     `function moveDiv(div, fps) {         var left = 0;         var param = 1;          function loop () {             update();             draw();         }          function update() {             left += param * 2;             if (left > 300) {                 left = 300;                 param = -1;             } else if (left < 0) {                 left = 0;                 param = 1;             }         }          function draw() {             div.style.left = left + "px";         }          setInterval(loop, 1000 / fps);     }     moveDiv(document.getElementById("div1"), 60);` 

效果如下:

[http://jsfiddle.net/livoras/4taf9hhs/embedded/result,js,html,css/](

) src="https://jsfiddle.net/livoras/4taf9hhs/embedded/result,js,html,css/" allowfullscreen="allowfullscreen" frameborder="0" class="loading" style="box-sizing: border-box; width: 825px; height: 300px; background: url("../img/loader.gif") 50% center no-repeat rgb(250, 250, 250);">

看看代码,我们让一个div在0 ~ 300px区间内左右来回移动。update计算更新描绘div的位置,draw重新描绘页面上的div。为了方便起见,这里直接使用setInterval作为定时器,实际情况下可以采用你喜欢的setTimeout或者requestAnimationFrame。这里设置每秒钟到更新60次,60fps是人尽皆知的比较适合做动画的帧率。

地球人都知道,JavaScript中的定时器是不准确的。由于JavaScript运行时需要耗费时间,而JavaScript又是单线程的,所以如果一个定时器如果比较耗时的话,是会阻塞下一个定时器的执行。所以即使你这里设置了1000 / 60每秒60帧的帧率,在不同的浏览器平台的差异也会导致实际上你的没有60fps的帧率。

所以上面代码在一个手机上执行的时候可能有60fps的帧率,在另外一个手机上可能就只有30fps,更甚可能只有10fps。

我们模拟一下这种情况会有什么效果发生:

[http://jsfiddle.net/livoras/Lcv1jm53/embedded/result,js,html,css/](

) src="https://jsfiddle.net/livoras/Lcv1jm53/embedded/result,js,html,css/" allowfullscreen="allowfullscreen" frameborder="0" class="loading" style="box-sizing: border-box; width: 825px; height: 300px; background: url("../img/loader.gif") 50% center no-repeat rgb(250, 250, 250);">

这完全不对大头!

可以看到三个方块移动速度根本不在同一个channel上。想象一下一个超级马里奥游戏在10fps的情况会怎么样?按跳跃一下,你会看到马里奥以一种太空漫游的姿态在空中抛弧线。

导致这种情况的原因很简单,因为我们计算和绘制每个div位置的时候是在每帧更新,每帧移动2px。在60fps的情况下,我们1秒钟会执行60帧,所以小块每秒钟会移动60 * 2 = 120px;如果是30fps,小块每秒就移动30 * 2 = 60px,以此类推10fps就是每秒移动20px。

三个小块在单位时间内移动的距离不一样!

假如你现在要做一个超级马里奥的游戏,怎么做到可以在不同帧率的情况下让马里奥看起来还是那么迅速且帅气?

解决方案很明显。虽然不同的浏览器平台上的运行差异可能会导致帧率的不一致,但是有一样东西是在任何平台上都一致的,那就是时间。所以我们可以改良我们的算法,不是以帧为基准来更新方块的位置,而是以时间为单位更新。也就是说,我们之前是px/frame,现在换成px/ms

这就是接下来要说的基于时间(Time-based)的动画算法。

基于时间的动画算法(Time-based)


其实思路和实现都很简单。我们计算每一帧离上一帧过去了多少时间,然后根据过去的时间来更新方块的位置。

例如,上面的方块应该每秒钟移动120px,每毫秒移动120 / 1000 = 0.12像素(12px/ms)。如果上一帧方块的位置在left为10px的位置,到了这一帧的时候,假设相对于上一帧来说时间过去了200ms,那在时间上来说在这一帧方块应该移动200ms * 0.12px/ms = 240px。最终位置应该为10 + 240 = 250px。其实就是left = left + detalTime * speed。代码如下:

     `function moveDivTimeBased(div, fps) {         var left = 0;         var current = +new Date;         var previous = +new Date;         var param = 1;          function loop() {             var current = +new Date;             var dt = current - previous; // 计算时间差             previous = current;             update(dt);             draw()         }          function update(dt) {             left += param * (dt * 0.12); // 根据时间差更新位置             if (left > 300) {                 left = 300;                 param = -1;             } else if (left < 0) {                 left = 0;                 param = 1;             }         }                  function draw() {             div.style.left = left + "px";         }          setInterval(loop, 1000 / fps);     }` 

看看效果如何:

[http://jsfiddle.net/livoras/8da1nssL/embedded/result,js,html,css/](

)

看起来比上面的好多了,30fps和10fps好像能勉强赶上60fps的步伐。但是时间久了会发现30fps和10fps越来越落后于60fps。(建议先刷新再看看效果会更加明显)

这是因为每次小方块碰到边缘的时候,都会损失掉一部分时间,而且帧率越低的损失越大。看看我们上面的update函数:

        `function update(dt) {           left += param * (dt * 0.12); // 根据时间差更新位置           if (left > 300) {               left = 300;               param = -1;           } else if (left < 0) {               left = 0;               param = 1;           }       }`  ### 常用的JavaScript设计模式  * 单体模式  * 工厂模式  * 例模式    ![](https://s2.51cto.com/images/20210927/1632727028781674.jpg)  ### 函数  * 函数的定义  * 局部变量和全局变量  * 返回值  * 匿名函数  * 自运行函数  * 闭包    **[开源分享:【大厂前端面试题解析+核心总结学习笔记+真实项目实战+最新讲解视频】](https://ali1024.coding.net/public/P7/Web/git)**    ![](https://s2.51cto.com/images/20210927/1632727029966406.jpg)

本站由小牛团队全力维护,小牛十年了,大家已经步入中年 。本站源码全部经过团队成员测试并调试,价格可能比其它网站略贵几元钱,不解释!
小牛资源 » JavaScript基于时间的动画算法,前端开发学习方法【附源码】_mb6130d15434330

发表评论

全站资源亲测可用,价格略高几元,不解释

立即查看 了解详情