专栏首页OECOMrequestAnimationFrame实现动画效果

requestAnimationFrame实现动画效果

html动画一般会采用css3的形式去做,当然也比较建议用css去做动画。但是有时候一些动画只能使用js来完成,常用的js动画方案是使用计时器来完成。编写动画循环的一个关键在于我们要延迟多长时间比较合适,如何设置时间才能让动画显得平滑顺畅,这个时间并不是越小越好,因为要遛狗足够的时间间隔来让浏览器产生渲染变化,否则就会变成跳跃感。

目前大多数的电脑显示器的刷新频率是60Hz,也就是一秒钟绘制60次,一般我们成为fps。大多数的浏览器都会对重绘操作进行限制,但是不会超过浏览器的频率,即使超过了,用户体验也不会有所提升。因此,最佳的循环时间就是1000/60,大约16.6毫秒。

了解过事件循环机制的朋友应该知道,siteTimeout和setInterval并不是精准的时间间隔,他们要等待其他优先的执行队列执行完成以后才能继续执行。

于是就引入了一个新的动画执行方式-- window.requestAnimationFrame()。它告诉浏览器——你希望执行一个动画,并且要求浏览器在下次重绘之前调用指定的回调函数更新动画。该方法需要传入一个回调函数作为参数,该回调函数会在浏览器下一次重绘之前执行。

它采用的是系统时间间隔,以保证最佳的绘制效率,不会因为时间过短造成过度绘制,也不会因为时间间隔太长,产生动画卡顿的现象。让各种网页动画效果能够有一个统一的刷新机制,从而节省系统资源,提高系统性能,改善视觉效果。

特点

  • requestAnimationFrame会把每一帧中的所有DOM操作集中起来,在一次重绘或回流中就完成,并且重绘或回流的时间间隔紧紧跟随浏览器的刷新频率
  • 在隐藏或不可见的元素中,requestAnimationFrame将不会进行重绘或回流,这当然就意味着更少的CPU、GPU和内存使用量
  • requestAnimationFrame是由浏览器专门为动画提供的API,在运行时浏览器会自动优化方法的调用,并且如果页面不是激活状态下的话,动画会自动暂停,有效节省了CPU开销

兼容性

具体兼容性如下图所示

应用

requestAnimationFrame的用法与settimeout很相似,只是不需要设置时间间隔而已。requestAnimationFrame使用一个回调函数作为参数,这个回调函数会在浏览器重绘之前调用。它返回一个整数,表示定时器的编号,这个值可以传递给cancelAnimationFrame用于取消这个函数的执行

let retID = requestAnimationFrame(callback);

取消的话可直接使用canceAnimationFrame来进行取消即可

cancelAnimationFrame(retID)

调用一次只会执行一次,所以正确的循环调用方式如下:

var count = 0;
function step() {
    count++;
    console.log(count)
  if (count > 6000) {
    window.cancelAnimationFrame(step);
  }else{
     window.requestAnimationFrame(step);
  }
}
step();

因为requestAnimationFrame有一定的兼容性,所以我们需要对齐进行兼容处理

window.requestAnimat = (function(){
    return window.requestAnimationFrame ||
            window.webkitRequestAnimationFrame  ||
            window.mozRequestAnimationFrame || function(callback){
                setTimeout(callback,1000/60);
            }
        })();
if (!window.cancelAnimationFrame) {
    window.cancelAnimationFrame = function(id) {
        clearTimeout(id);
    };
}

下面来看一下具体的应用效果,下面的示例是模拟一个进度条

<div id="myDiv" style="background-color: lightblue;width: 0;height: 20px;line-height: 20px;">0%</div>
<button id="btn">run</button>
<script>
var timer;
btn.onclick = function(){
    myDiv.style.width = '0';
    cancelAnimationFrame(timer);
    timer = requestAnimationFrame(function fn(){
        if(parseInt(myDiv.style.width) < 500){
            myDiv.style.width = parseInt(myDiv.style.width) + 5 + 'px';
            myDiv.innerHTML =     parseInt(myDiv.style.width)/5 + '%';
            timer = requestAnimationFrame(fn);
        }else{
            cancelAnimationFrame(timer);
        }    
    });
}
</script>

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • nodejs开发微信支付之接收退款申请通知

    nodejs申请退款之后,微信服务器会将退款结果通知服务器,我们需要接收处理一下。特别说明:退款结果对重要的数据进行了加密,商户需要用商户秘钥进行解密后才能获得...

    无邪Z
  • react-router之onEnter和onLeave

    在之前介绍过react-router的使用,在这里我们介绍一下路由的onEnter和onLeave,顾名思义,分别是路由进入之前和路由离开之前,我们可以在这段时...

    无邪Z
  • 浏览器同源策略及规避方式

    同源,何为同源,同源的意思就是协议、端口、域名三者均需要相同才能构成同源。例如 这个域名来说,https://为协议,www.oecom.cn为域名,默认的端...

    无邪Z
  • 写给大忙人看的 Flink Window原理

    Window 可以说是 Flink 中必不可少的 operator 之一,在很多场合都有很非凡的表现。今天呢,我们就一起来看一下 window 是如何实现的。

    shengjk1
  • 设置WPF窗体全屏显示:

    //全屏代码: private void Window_Loaded(object sender, RoutedEventArgs e) { // 设...

    hbbliyong
  • OpenGL-第一个程序-基于GLFW、GL3W

    环境配置教程-> https://blog.csdn.net/jiuzaizuotian2014/article/details/82915917 配置gl...

    祝你万事顺利
  • Window对象的判定方法

    /* window对象的判定,由于ECMA是不规范Host对象,window对象属于Host, 所以也没有约定,所以就算是Object.prototype也对它...

    郑小超.
  • JavaScript Window - 浏览器对象模型

    浏览器对象模型 (BOM) 使 JavaScript 有能力与浏览器“对话”。 浏览器对象模型 (BOM) 浏览器对象模型(Browser Object Mod...

    李海彬
  • JavaScript 学习(2)

    参考: http://www.w3cschool.cc/js/js-window.html

    lpe234
  • 聊聊flink Table的Group Windows

    flink-table_2.11-1.7.0-sources.jar!/org/apache/flink/table/api/table.scala

    codecraft

扫码关注云+社区

领取腾讯云代金券