requestAnimationFrame

window.requestAnimationFrame() 用浏览器刷新频率(通常是每秒60/75次)执行一个动画,并且要求浏览器在下次重绘之前调用指定的回调函数更新动画。该方法需要传入一个回调函数作为参数,该回调函数会在浏览器下一次重绘之前执行。

优点

【1】requestAnimationFrame会把每一帧中的所有DOM操作集中起来,在一次重绘或回流中就完成,并且重绘或回流的时间间隔紧紧跟随浏览器的刷新频率

【2】在隐藏或不可见的元素中,requestAnimationFrame将不会进行重绘或回流,这当然就意味着更少的CPU、GPU、电池和内存使用量

【3】requestAnimationFrame是由浏览器专门为动画提供的API,在运行时浏览器会自动优化方法的调用,并且如果页面不是激活状态下的话,动画会自动暂停,有效节省了CPU开销

注意:若你想在浏览器下次重绘之前继续更新下一帧动画,那么回调函数自身必须再次调用window.requestAnimationFrame()

语法

window.requestAnimationFrame(callback);

参数:callback

  1. 该回调函数会被传入DOMHighResTimeStamp参数,该参数与performance.now()的返回值相同。它表示requestAnimationFrame() 页面从加载渲染到现在的时间(即开始去执行回调函数的时刻)。
  2. performance.now()是当前时间与performance.timing.navigationStart的时间差,以微秒(百万分之一秒)为单位的时间,与 new performance.timing.navigationStart的区别是不受系统程序执行阻塞的影响,因此更加精准。
  3. IE9 自身没有 performance.now(),使用 new Date().getTime()-performance.timing.navigationStart 替代。
  4. 如果函数此参数不需要可以不传。

返回值

一个 long 整数,请求 ID ,是回调列表中唯一的标识。是个非零值。你可以传这个值给 window.cancelAnimationFrame() 以取消回调函数。

浏览器兼容性

表中的数字指定了完全支持requestAnimationFrame()方法的第一个浏览器版本:

Method
requestAnimationFrame() 24 23 15 6.1 10

兼容示例

// requestAnimationFrame 兼容函数
function requestAnimation(){
    // 低版本兼容处理
    window.requestAnimationFrame = window.requestAnimationFrame || 
                                      window.mozRequestAnimationFrame ||
                                      window.webkitRequestAnimationFrame ||
                                   window.msRequestAnimationFrame;

    window.cancelAnimationFrame = window.cancelAnimationFrame ||
                                   window.mozCancelAnimationFrame ||
                                   window.webkitCancelAnimationFrame ||
                                     window.msCancelAnimationFrame || 
                                     window.webkitCancelRequestAnimationFrame;

        var performance_now=0;// 性能监测时间

    if (!window.requestAnimationFrame) {

        window.requestAnimationFrame = function(callback) {
            // 执行间隔时间
            var exceTime = 1000/60; // 16.7
            
            // var id = window.setTimeout(function() {
               //   // console.dir(performance)
               //   // IE 方法获取   performance.now(),IE9 自身没有 performance.now(),其他版本未测试
               //   performance_now=new Date().getTime()-performance.timing.navigationStart
               //   // callback 中的时间参数是模拟 requestAnimationFrame 回调函数中系统自带的时间参数;
            //      callback(performance_now);
            // }, exceTime);

            // 不传递时间参数写法,如果传递时间参数用上面的注释部分
            var id=setTimeout(callback,exceTime)
           
            return id;
        };
    }

    // 关闭定时器
    if (!window.cancelAnimationFrame) {
        window.cancelAnimationFrame = function(id) {
            clearTimeout(id);
        };
    }
}

动画示例,不添加额外参数

js 部分

window.onload=function(argument) {
    // 调用兼容函数
    requestAnimation();
    // 示例
    var progress = 0;
    var ele = document.getElementById("test");
    var btn=document.getElementById("run")
    var time_id=null;

    btn.onclick=function(){
        // requestAnimationFrame 自身有一个回调函数,回调函数有一个系统自带时间参数
        time_id=requestAnimationFrame(step);
    }

    // 计算函数执行时间变量
    var lastTime = new Date().getTime();
    var currTime = 0 ; //
    var diff=-1; // -1 是一个标记数值,每次运行的间隔时间

    // 运动函数,timestamp(毫秒值) 函数自带时间参数,为页面从性能检测(加载渲染)开始到现在的时间
    function step(timestamp) {

        // 计算函数执行间隔时间部分
        if(timestamp){
            // 当前时间毫秒
            currTime=new Date().getTime();
            // 第一次进入
            if(diff==-1){
                diff = timestamp - (currTime-lastTime)
            }else{
                diff = timestamp - lastTime
            }
            // 打印这次运行时间与下次运行时间的差值
            console.log(parseInt(diff),'---',timestamp)
        }
    

        // 具体函数 开始
        if (progress < 100) {
            progress += 1;
            ele.style.width = progress + "%";
            ele.innerHTML=progress + "%";
            time_id=requestAnimationFrame(step);
        }else{
            cancelAnimationFrame(time_id)
        }

        // 更新最后时间
        lastTime=timestamp
     
    }
    
}

html 部分

<div id="test" style="width:0px;height:17px;background:#0f0;">0%</div>
<input type="button" value="Run" id="run"/>

完整示例

  1 <!DOCTYPE html>
  2 <html lang="en">
  3 <head>
  4     <meta charset="UTF-8">
  5     <title>requestAnimationFrame</title>
  6     <script type="text/javascript">
  7     window.onload=function(argument) {
  8         // 调用兼容函数
  9         requestAnimation();
 10         // 示例
 11         var progress = 0;
 12         var ele = document.getElementById("test");
 13         var btn=document.getElementById("run")
 14         var time_id=null;
 15 
 16         btn.onclick=function(){
 17             // requestAnimationFrame 自身有一个回调函数,回调函数有一个系统自带时间参数
 18             time_id=requestAnimationFrame(step);
 19         }
 20 
 21         // 计算函数执行时间变量
 22         var lastTime = new Date().getTime();
 23         var currTime = 0 ; //
 24         var diff=-1; // -1 是一个标记数值,每次运行的间隔时间
 25 
 26         // 运动函数,timestamp(毫秒值) 函数自带时间参数,为页面从性能检测(加载渲染)开始到现在的时间
 27         function step(timestamp) {
 28 
 29             // 计算函数执行间隔时间部分
 30             if(timestamp){
 31                 // 当前时间毫秒
 32                 currTime=new Date().getTime();
 33                 // 第一次进入
 34                 if(diff==-1){
 35                     diff = timestamp - (currTime-lastTime)
 36                 }else{
 37                     diff = timestamp - lastTime
 38                 }
 39                 // 打印这次运行时间与下次运行时间的差值
 40                 console.log(parseInt(diff),'---',timestamp)
 41             }
 42         
 43 
 44             // 具体函数 开始
 45             if (progress < 100) {
 46                 progress += 1;
 47                 ele.style.width = progress + "%";
 48                 ele.innerHTML=progress + "%";
 49                 time_id=requestAnimationFrame(step);
 50             }else{
 51                 cancelAnimationFrame(time_id)
 52             }
 53 
 54             // 更新最后时间
 55             lastTime=timestamp
 56          
 57         }
 58         
 59     }
 60 
 61     // requestAnimationFrame 兼容函数
 62     function requestAnimation(){
 63         // 低版本兼容处理
 64         window.requestAnimationFrame = window.requestAnimationFrame || 
 65                                           window.mozRequestAnimationFrame ||
 66                                           window.webkitRequestAnimationFrame ||
 67                                        window.msRequestAnimationFrame;
 68 
 69         window.cancelAnimationFrame = window.cancelAnimationFrame ||
 70                                        window.mozCancelAnimationFrame ||
 71                                        window.webkitCancelAnimationFrame ||
 72                                          window.msCancelAnimationFrame || 
 73                                          window.webkitCancelRequestAnimationFrame;
 74 
 75          var performance_now=0;// 性能监测时间
 76 
 77         if (!window.requestAnimationFrame) {
 78 
 79             window.requestAnimationFrame = function(callback) {
 80                 // 执行间隔时间
 81                 var exceTime = 1000/60; // 16.7
 82                 
 83                 var id = window.setTimeout(function() {
 84                      // console.dir(performance)
 85                      // IE 方法获取 performance.now(),IE9 自身没有 performance.now(),其他版本未测试
 86                      performance_now=new Date().getTime()-performance.timing.navigationStart
 87                      // callback 中的时间参数是模拟 requestAnimationFrame 回调函数中系统自带的时间参数;
 88                      callback(performance_now);
 89                 }, exceTime);
 90 
 91                 // 不传递时间参数写法
 92                 //var id=setTimeout(callback,exceTime)
 93                
 94                 return id;
 95             };
 96         }
 97 
 98         // 关闭定时器
 99         if (!window.cancelAnimationFrame) {
100             window.cancelAnimationFrame = function(id) {
101                 clearTimeout(id);
102             };
103         }
104     }
105 
106     </script>
107 </head>
108 <body>
109     <div id="test" style="width:0px;height:17px;background:#0f0;">0%</div>
110     <input type="button" value="Run" id="run"/>
111 </body>
112 </html>
View Code

封装动画,传递参数

js 部分

window.onload=function(){
    var progress = 1,startTime=0,passTime=0;
    var eleId = document.getElementById("test");
    var btn=document.getElementById("run");
    var runTime=2000;// 动画运动时间
    var runLeft=500; // 动画运动距离
    var requestId=null;

    requestAnimation()

    btn.onclick=function(){

        // eleId 运动元素
        // timeSpart 运动时间函数
        // 动画运动总时长
        // function 具体运动
        move(timeSpart,runTime,function(parem_bite){
            //浏览器不支持 translateX
            if(isPropertySupported('transform')){
                eleId.style.transform='translateX('+parem_bite * runLeft +'px)'
            }else{
                eleId.style.left=parem_bite * runLeft +'px'
            }
            eleId.innerHTML=parem_bite*runLeft + "px";
        })
    }
}
// 运动
function move(timeFun,runTime,callback){
    // 声明临时起始时间,仅第一次时使用
    // 如果浏览器有performance.now() 函数
    if(('now' in performance)){ 
         var startTime=performance.now()
    }else{
        var startTime=new Date().getTime()-performance.timing.navigationStart
    }

    requestId=requestAnimationFrame(function fn(now){
        // 从执行函数到现在已过时间
        passTime=now-startTime
        // 已过时间与总时间的比例
        var bite= passTime / runTime

        if(bite>=1){
            bite=1
        }
        // 具体运动,传递时间比例
        callback(timeFun(bite))

        // 判断条件
        if(bite<1){    
            requestId=requestAnimationFrame(fn)                    
        }

        // 关闭运动
        if(bite==1){
            cancelAnimationFrame(requestId)
        }
    })
}

// 时间运动函数
function timeSpart(time_bite){
    return time_bite*time_bite
}

//CSS3属性是否支持,支持返回true,不支持返回false,不支持ie6
//如果坚持background-color, 要用backgroundColor替换 background-color
function isPropertySupported(property)
{
    return property in document.body.style;
}

html 部分

<div id="test">0px</div>
<input type="button" value="Run" id="run"/>

完整示例

  1 <!DOCTYPE html>
  2 <html lang="en">
  3 <head>
  4     <meta charset="UTF-8">
  5     <title>requestAnimationFrame</title>
  6     <style type="text/css">
  7     div{transform: translateX(0px);width:100px;height:100px;background:#0f0; position: relative;}
  8     </style>
  9     <script type="text/javascript">
 10     window.onload=function(){
 11         var progress = 1,startTime=0,passTime=0;
 12         var eleId = document.getElementById("test");
 13         var btn=document.getElementById("run");
 14         var runTime=2000;// 动画运动时间
 15         var runLeft=500; // 动画运动距离
 16         var requestId=null;
 17 
 18         requestAnimation()
 19 
 20         btn.onclick=function(){
 21 
 22             // eleId 运动元素
 23             // timeSpart 运动时间函数
 24             // 动画运动总时长
 25             // function 具体运动
 26             move(eleId,timeSpart,runTime,function(parem_bite){
 27                 //浏览器不支持 translateX
 28                 if(isPropertySupported('transform')){
 29                     eleId.style.transform='translateX('+parem_bite * runLeft +'px)'
 30                 }else{
 31                     eleId.style.left=parem_bite * runLeft +'px'
 32                 }
 33                 eleId.innerHTML=parem_bite*runLeft + "px";
 34             })
 35         }
 36     }
 37 
 38 
 39     // 运动
 40     function move(ele,timeFun,runTime,callback){
 41         // 声明临时起始时间,仅第一次时使用
 42         // 如果浏览器有performance.now() 函数
 43         if(('now' in performance)){ 
 44              var startTime=performance.now()
 45         }else{
 46             var startTime=new Date().getTime()-performance.timing.navigationStart
 47         }
 48 
 49         requestId=requestAnimationFrame(function fn(now){
 50             // 从执行函数到现在已过时间
 51             passTime=now-startTime
 52             // 已过时间与总时间的比例
 53             var bite= passTime / runTime
 54 
 55             if(bite>=1){
 56                 bite=1
 57             }
 58             // 具体运动,传递时间比例
 59             callback(timeFun(bite))
 60 
 61             // 判断条件
 62             if(bite<1){    
 63                 requestId=requestAnimationFrame(fn)                    
 64             }
 65 
 66             // 关闭运动
 67             if(bite==1){
 68                 cancelAnimationFrame(requestId)
 69             }
 70         })
 71     }
 72 
 73     // 时间运动函数
 74     function timeSpart(time_bite){
 75         return time_bite*time_bite
 76     }
 77 
 78     //CSS3属性是否支持,支持返回true,不支持返回false,不支持ie6
 79     //如果坚持background-color, 要用backgroundColor替换 background-color
 80     function isPropertySupported(property)
 81     {
 82         return property in document.body.style;
 83     }
 84 
 85 
 86     // requestAnimationFrame 兼容函数
 87     function requestAnimation(){
 88         // 低版本兼容处理
 89         window.requestAnimationFrame = window.requestAnimationFrame || 
 90                                           window.mozRequestAnimationFrame ||
 91                                           window.webkitRequestAnimationFrame ||
 92                                        window.msRequestAnimationFrame;
 93 
 94         window.cancelAnimationFrame = window.cancelAnimationFrame ||
 95                                        window.mozCancelAnimationFrame ||
 96                                        window.webkitCancelAnimationFrame ||
 97                                          window.msCancelAnimationFrame || 
 98                                          window.webkitCancelRequestAnimationFrame;
 99 
100          var performance_now=0;// 性能监测时间
101 
102         if (!window.requestAnimationFrame) {
103 
104             window.requestAnimationFrame = function(callback) {
105                 // 执行间隔时间
106                 var exceTime = 1000/60; // 16.7
107                 
108                 var id = window.setTimeout(function() {
109                      // console.dir(performance)
110                      // IE 方法获取 performance.now(),IE9 自身没有 performance.now(),其他版本未测试
111                      performance_now=new Date().getTime()-performance.timing.navigationStart
112                      // callback 中的时间参数是模拟 requestAnimationFrame 回调函数中系统自带的(性能)时间参数;
113                      callback(performance_now);
114                 }, exceTime);
115 
116                 // 不传递时间参数写法
117                 //var id=setTimeout(callback,exceTime)
118                
119                 return id;
120             };
121         }
122 
123         // 关闭定时器
124         if (!window.cancelAnimationFrame) {
125             window.cancelAnimationFrame = function(id) {
126                 clearTimeout(id);
127             };
128         }
129     }
130     </script>
131 </head>
132 <body>
133     <div id="test">0px</div>
134     <input type="button" value="Run" id="run"/>
135 </body>
136 </html>
View Code

相关文章:

requestAnimationFrame

Performance — 前端性能监控利器

window.requestAnimationFrame

posted @ 2022-12-17 16:55  柔和的天空  阅读(198)  评论(0编辑  收藏  举报