初识requestAnimationFrame

903 阅读2分钟

动画的实现方式

实现动画的方式有以下几种:

  1. css3 操作简单,也最普遍常用
  2. JS-setInterval 定时器,每隔一定执行某种操作
  3. JS-setTimeout 延迟触发,每隔一定执行触发某种操作
  4. JS-requestAnimationFrame H5新API

实例

    // Html
    <div class="css3 box">css3</div>
    <div id="box" class="box">setInterval</div>
    <div id="box1" class="box">setTimeout</div>
    <div id="box2" class="box">requestAnimationFrame</div>
    // css
    .css3 {
        animation: move linear forwards 1670ms;
    }
    @keyframes move {
        from {
            left: 0;
        }
        to {
            left: 500px;
        }
    }
    .box {
        position: absolute;
        width: 50px;
        height: 50px;
        background-color: cornflowerblue;
        left: 0;
    }
    #box {
        top: 100px;
    }
    #box1 {
        top: 200px;
    }
    #box2 {
        top: 300px;
    }
    let box = document.querySelector('#box');
    let box1 = document.querySelector('#box1');
    let box2 = document.querySelector('#box2');
    !function () {
        let index = 0;
        let _left = box.offsetLeft;
        let timer = setInterval(function () {
            if (index >= 100) {
                clearInterval(timer);
            } else {
                index++;
                box.style.left = _left + index*5 + 'px';
            }
        }, 16.7);
    }();
    !function () {
        let index = 0;
        let _left = box1.offsetLeft;

        function move() {
            index++;
            box1.style.left = _left + index*5 + 'px';
            if (index < 100) {
                setTimeout(move, 16.7);
            }
        }
        move();
    }();
    !function () {
        let index = 0;
        let _left = box2.offsetLeft;

        function render() {
            index++;
            box2.style.left = _left + index*5 + 'px';
            if (index < 100) {
                window.requestAnimationFrame(render);
            }
        }

        window.requestAnimationFrame(render);
    }();

从运行结果来看,requestAnimationFrame是最流畅的,如果把最终left定为100px,则css3requestAnimationFrame表现一致为最好。

抛弃

  1. setInterval 动画始终在抖动,失败
  2. setTimeout 动画会掉帧,偶尔出现跳动,失败

最终选择

  1. CSS3 适合简单的动画,内置曲线函数,针对opacity的动画有奇效
  2. requestAnimationFrame 最完美的JS动画,但是兼容性可能有问题,如果不兼容,就只能用setTimeout代替
  3. 第三方库 适合动画特别多且复杂的情境

requestAnimationFrame(rAF)

原理

电脑屏幕其实一直是不断变化的,它有个绘制频率,如果是60HZ,那就说明1000ms/60=16.7ms刷新一次屏幕,这个频率下人眼是识别不出来的,所以认定屏幕是不动的。那这个requestAnimationFrame它能保证回调函数在屏幕每一次的绘制间隔中只被执行一次,这样看起来就很流畅不会丢帧

兼容

因为不同的屏幕刷新频率是不同的,而且部分浏览器并不支持这个属性,所以需要兼容

    if (!Date.now)
        Date.now = function() { return new Date().getTime(); };
     
    (function() {
        'use strict';
         
        var vendors = ['webkit', 'moz'];
        for (var i = 0; i < vendors.length && !window.requestAnimationFrame; ++i) {
            var vp = vendors[i];
            window.requestAnimationFrame = window[vp+'RequestAnimationFrame'];
            window.cancelAnimationFrame = (window[vp+'CancelAnimationFrame']
                                       || window[vp+'CancelRequestAnimationFrame']);
        }
        if (/iP(ad|hone|od).*OS 6/.test(window.navigator.userAgent) // iOS6 is buggy
            || !window.requestAnimationFrame || !window.cancelAnimationFrame) {
            var lastTime = 0;
            window.requestAnimationFrame = function(callback) {
                var now = Date.now();
                var nextTime = Math.max(lastTime + 16, now);
                return setTimeout(function() { callback(lastTime = nextTime); },
                                  nextTime - now);
            };
            window.cancelAnimationFrame = clearTimeout;
        }
    }());

cancelAnimationFrame(callback)自然就是取消动画