您的位置:首页 > 产品设计 > UI/UE

requestAnimationFrame--用法及轮播动画

2017-08-08 20:09 549 查看
requestAnimationFrame ,字面含义是请求动画帧。从API命名来看,和动画有着密切的关系。其用法跟setTimeout差不多,与setTimeout相比,最大的优势是 由浏览器来决定函数的执行时机

形象一点的解释就是:告诉浏览器说 “我这里有一个函数要执行,你有空了帮忙执行一下”,然后浏览器相对比较空闲的时候就给执行了。

用法一:动画

raf api本身的设计就是用来解决js动画的性能问题。那么,为什么raf做动画性能会更好呢?主要原因在于 raf更加智能,它并非加快执行速度,而是适当时候降帧,防止并解决丢帧问题 。当它发现无法维持60fps的频率时,它会把频率降低到30fps来保持帧数的稳定。也就是说如果上一次raf的回调执行时间过长,那么触发下一次raf回调的时间就会缩短,反之亦然,这也是为什么说由浏览器来决定执行时机性能会更好。

(function animloop(){
window.requestAnimFrame(animloop);
render();
})();


用法二: 函数节流

在高频率事件中,为了防止16ms内发生多次函数执行,使用raf可保证16ms内只触发一次,这既能保证流畅性也能更好的节省函数执行的开销。 16ms内函数执行多次没有意义,因为显示器16ms刷新一次,多次执行并不会在界面上有任何显示。

举个例子:

var $box = $('#J_num2'),
$point = $box.find('i');
$box.on('mousemove',function(e){
requestAnimationFrame(function(){
$point.css({
top : e.pageY,
left : e.pageX
})
})
})


用法三:CPU节能

raf的另一个特性是:如果页面不是激活状态下的话,函数会自动暂停,有效节省了CPU开销。

在移动端,如果页面中有自动播放的轮播图、倒计时或使用 setTimeout/setInterval 来执行任务的定时器。那么 当app进到后台或是锁屏后,webviewcorethread仍然持续占用CPU,导致耗电 。而使用raf可以很简单的解决此类问题。

(function(){
var timer;
var $txt = $('#J_num2'),
num = 0;
function play(){
timer = setTimeout(function(){
//使用raf实现非激活状态下不运行
requestAnimationFrame(function(){
stop();
next();
});
},1000)
}

function stop(){
clearTimeout(timer)
}

function next(){
$txt.text(num++);
play();
}
play();
})();


用法四:分帧初始化

都知道,raf的执行时间约为16.7ms,即为一帧。那么可以使用raf将页面初始化的函数进行打散到每一帧里,这样 可以在初始化时降低CPU及内存开销 。

很多页面,初始化加载时,CPU都会有很明显的波动,就是因为大量的操作都集中到了一点上。

举个例子:

页面中有4个模块,A、B、C、D,在页面加载时进行实例化,一般的写法类似于:

$(function(){
new A();
new B();
new C();
new D();
})


而使用raf可将每个模块分别初始化,即 每个模块都有16ms的初始化时间

$(function(){
var lazyLoadList = [A,B,C,D];
$.each(lazyloadList, function(index, module){
window.requestAnimationFrame(function(){new module()});
});

})


用法五:异步化

raf实际是一种异步化的操作,曾经 setTimeout(function(){},0) 一度成为解决了很多前端疑难杂症的法宝。而现在,可以用raf来代替。

这么多好处,

用setTimeout和setInterval来实现动画-缺点

1、对调用动画的循环机制没有进行优化

2、即使传递毫秒为单位的参数,也不能打到ms的准确性。因为JavaScript是单线程的,可能发生阻塞

3、没有考虑绘制动画的最佳时机

requestAniamationFrame兼容

requestAnimationFrame 不需要使用者指定循环间隔时间,浏览器会基于当前页面是否可见、CPU的负荷情况等来自行决定最佳的帧速率,从而更合理地使用CPU。

如果想做逐帧动画,就应该用这个方法,这就要求动画函数执行会先于浏览器重绘动作。通常,被调用的频率是每秒60次。

回调函数只会传入一个DOMHighResTimeStamp参数,表示函数队列被触发的时间。

requestAnimationFrame返回一个id,用于window.cancelAnimationFrame(id)来取消这个回调函数。

兼容代码:

window.requestAnimationFrame=window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.oRequestAnimationFrame ||
window.msRequestAnimationFrame ||

function (callback, element) {
var start,
finish;

window.setTimeout(function () {
start = +new Date();
callback(start);
finish = +new Date();

self.timeout = 1000 / 60 - (finish - start);

}, self.timeout);
};
window.cancelNextRequestAnimationFrame = window.cancelRequestAnimationFrame
|| window.webkitCancelAnimationFrame
|| window.webkitCancelRequestAnimationFrame
|| window.mozCancelRequestAnimationFrame
|| window.oCancelRequestAnimationFrame
|| window.msCancelRequestAnimationFrame
|| clearTimeout;


requestAnimationFrame–轮播动画

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<style>
*{padding:0;margin: 0}
.outer{width: 100px;height: 100px;overflow:hidden;position: relative;}
.inner{
height:100px;list-style-type:none;width: 400px;
}
.inner:after{height: 0;content: '';clear: both;visibility: hidden;}
.inner li{float: left;width: 100px;height: 100px}
li:nth-child(1){background: red}
li:nth-child(2){background: black}
li:nth-child(3){background: yellow}
li:nth-child(4){background: green}
</style>
</head>
<body>
<div class="outer">
<ul class="inner">
<li></li>
<li></li>
<li></li>
<li></li>
</ul>
</div>

<button>下一步</button>
<script type="text/javascript">
var start = null;
var element = document.querySelector('.inner')
element.style.position = 'absolute';
var cur=0,mm=100,timeid
function step(timestamp) {
if (!start) start = timestamp;
var progress = timestamp - start;
if(cur==3){
element.style.left=0;
}else{
element.style.left = -Math.min(progress / 10+cur*100, (cur+1)*100) + 'px';
}

if (progress < 1000) {
timeid=window.requestAnimationFrame(step);
}else{
cur=cur<3?cur+1:0
window.cancelAnimationFrame(timeid)
timeid=null
start=null
setTimeout(auto,1000)
}
}
var btn=document.querySelector('button')
btn.onclick=function(){
auto()
}
function auto(){
if(!timeid){
console.log(cur)
timeid=window.requestAnimationFrame(step);
}
}
</script>
</body>
</html>


参考:http://outofmemory.cn/html/javascript-animation-practice

http://blog.csdn.net/github_37037281/article/details/68957690
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: