requestAnimationFrame优化动画

本文由清尘发表于2018-05-05 17:25最后修改于2020-07-30属于HTML/CSS分类

在过去,为了使用JavaScript脚本代码实现动画,开发者需要使用一个定时器来指定每隔一段时间使页面显示效果产生一些变化。最近,浏览器厂商决定提供一些API来优化动画的实现方法。于是,在HTML 5新增window.requestAnimFrame方法,用于以一种更好的性能来实现动画。
通过window.requestAnimFrame方法,浏览器可以具有将各种并发性动画结合入一个单一的页面进行创建及渲染的能力,这种能力将使得动画的实现具有更好的性能。例如,可以同时执行使用JavaScript脚本代码实现的动画与使用CSS中的transition样式属性实现的动画。另外,通过window.requestAnimFrame方法,当用户将浏览器标签窗口切换到其他标签窗口时,当前页面中的动画将被暂停运行,以减少CPU、GPU与内存的消耗。


window.requestAnimFrame = (function(){
    return  window.requestAnimationFrame       ||
                window.webkitRequestAnimationFrame ||
                window.mozRequestAnimationFrame    ||
                window.oRequestAnimationFrame      ||
                window.msRequestAnimationFrame     ||
                function(callback){
                   window.setTimeout(callback, 1000 / 60);// 定义每秒执行60次动画
                };
})();
// 相当于使用setInterval(render, 16)方法,但是具有更高的性能
(function animloop(){
        requestAnimFrame(animloop);
        render();
})();

通过window.requestAnimFrame方法在canvas画布中绘制一个小球运动动画

window.requestAnimFrame = (function(){
    return  window.requestAnimationFrame       ||
            window.webkitRequestAnimationFrame ||
            window.mozRequestAnimationFrame    ||
            window.oRequestAnimationFrame      ||
            window.msRequestAnimationFrame     ||
            function(){
                window.setTimeout(callback, 1000 / 60); // 每秒60帧
            };
})();
var canvas, context;
init();
animate();
function init() {
    canvas = document.createElement('canvas');
    canvas.style.left=0;
    canvas.style.top=0;
    canvas.width = 210;
    canvas.height = 210;
    context = canvas.getContext('2d');
    document.body.appendChild( canvas );
}
function animate() {
    requestAnimFrame( animate );
    draw();
}
function draw() {
    var time = new Date().getTime() * 0.002;
    var x = Math.sin( time ) * 96 +105;
    var y = Math.cos( time * 0.9 ) * 96 + 105;
    context.fillStyle ='pink';
    context.fillRect( 0, 0, 255, 255 );
    context.fillStyle='rgb(255,0,0)';
    context.beginPath();
    context.arc(x,y,10,0,Math.PI * 2,true);
    context.closePath();
    context.fill();
}

requestAnimationFrame设置进度条效果

 <div id="box" class="box"></div>
 .box{height:20px; background-color: red; width: 1px;}
var g_width = 10;
var box = $('#box');
window.requestAnimFrame = (function(){
  return  window.requestAnimationFrame       ||
          window.webkitRequestAnimationFrame ||
          window.mozRequestAnimationFrame    ||
          function( callback ){
            window.setTimeout(callback, 1000 / 60);
          };
})();

function animloop(){
  requestAnimFrame(animloop);
  if(g_width < 500){
    render();
  }

}

function render(){
    var cur_w = box.css('width',g_width+'px');
    g_width++;
    console.log(g_width)
}

animloop();

================

以下来自《javascript框架设计(第2版)》内容:

给出真正可用的兼容版本

// by 司徒正美 基于网友屈屈与月影的版本改进而来
// https://github.com/wedteam/qwrap-components/blob/master/animation/anim.frame.js
function getAnimationFrame() {
    //不存在msRequestAnimationFrame,IE10与Chrome24直接用:requestAnimationFrame
    if (window.requestAnimationFrame) {
        return {
            request: requestAnimationFrame,
            cancel: cancelAnimationFrame
        }
        //Firefox11-没有实现cancelRequestAnimationFrame
        //并且mozRequestAnimationFrame与标准出入过大
    } else if (window.mozCancelRequestAnimationFrame && window.mozCancelAnimationFrame) {
        return {
            request: mozRequestAnimationFrame,
            cancel: mozCancelAnimationFrame
        }
    } else if (window.webkitRequestAnimationFrame && webkitRequestAnimationFrame(String)) {
        return {//修正某个特异的webKit版本下没有time参数
            request: function(callback) {
                return window.webkitRequestAnimationFrame(
                        function() {
                            return callback(new Date - 0);
                        }
                );
            },
            cancel: window.webkitCancelAnimationFrame || 
              window.webkitCancelRequestAnimationFrame
        }
    } else {
        var millisec = 25;     //40fps;
        var callbacks = [];
        var id = 0, cursor = 0;
        function playAll() {
            var cloned = callbacks.slice(0);
            cursor += callbacks.length;
            callbacks.length = 0; //清空队列
            for (var i = 0, callback; callback = cloned[i++]; ) {
                if (callback !== "cancelled") {
                    callback(new Date - 0);
                }
            }
        }
        window.setInterval(playAll, millisec);
        return {
            request: function(handler) {
                callbacks.push(handler);
                return id++;
            },
            cancel: function(id) {
                callbacks[id - cursor] = "cancelled";
            }
        };
    }
}