requestAnimationFrame
window.requestAnimationFrame() 用浏览器刷新频率(通常是每秒60/75次)执行一个动画,并且要求浏览器在下次重绘之前调用指定的回调函数更新动画。该方法需要传入一个回调函数作为参数,该回调函数会在浏览器下一次重绘之前执行。
优点
【1】requestAnimationFrame会把每一帧中的所有DOM操作集中起来,在一次重绘或回流中就完成,并且重绘或回流的时间间隔紧紧跟随浏览器的刷新频率
【2】在隐藏或不可见的元素中,requestAnimationFrame将不会进行重绘或回流,这当然就意味着更少的CPU、GPU、电池和内存使用量
【3】requestAnimationFrame是由浏览器专门为动画提供的API,在运行时浏览器会自动优化方法的调用,并且如果页面不是激活状态下的话,动画会自动暂停,有效节省了CPU开销
注意:若你想在浏览器下次重绘之前继续更新下一帧动画,那么回调函数自身必须再次调用window.requestAnimationFrame()
语法
window.requestAnimationFrame(callback);
参数:callback
- 该回调函数会被传入
DOMHighResTimeStamp
参数,该参数与performance.now()
的返回值相同。它表示requestAnimationFrame() 页面从加载渲染到现在的时间(即开始去执行回调函数的时刻)。 - performance.now()是当前时间与performance.timing.navigationStart的时间差,以微秒(百万分之一秒)为单位的时间,与 new performance.timing.navigationStart的区别是不受系统程序执行阻塞的影响,因此更加精准。
- IE9 自身没有 performance.now(),使用 new Date().getTime()-performance.timing.navigationStart 替代。
- 如果函数此参数不需要可以不传。
返回值
一个 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>
封装动画,传递参数
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>
相关文章: