request AnimationFrame的应用
1.在requestAnimationFrame出现之前,做基于js的动画一般会使用setTimeout来按一定时间间隔来修改css属性值或其他dom的操作来达到动画的效果,但是setTimeout这个函数只能保证你每隔指定的时间将要执行的代码输出到执行的队列中,这就意味在代码插入之前可能还有代码在执行之中的,这就造成你所期待的动画未能及时变换,造成动画不流畅的重要原因,后来才有了这个requestAnimationFrame新的API,它是HTML5的一部分,它系将浏览器刷新重绘(浏览器一般重绘的频率在60HZ左右)之前透过requestAnimationFrame来通知即将要播放下一帧的动画,该方法有一个参数作为回调函数,我们可以讲下一帧的动画操作作为该回调函数,并且回调函数会自动被传入一个时间截参数,表示执行回调函数的那个时刻,将这个时刻与刚开始执行动画的时刻进行比较,我们可以精确得出动画系该时刻应该播放到的进度是怎样的,而且每调用该方法会返回一个整型的id值,获得这个值可以通过cancelAnimationFrame来取消动画的执行。实际上是一个对动画帧的一个管理,只不过将这个任务交给浏览器厂商自己做会更加好的时候,就有了这个requestAnimationFrame API的出现,如果浏览器版本不支持的话可以用setTimeout(cb,1000/60)来代替requestAnimationFrame(cb),但系效果肯定是唔够后者好的。
2.做一个实际的例子,一个是基于对属性值修改的,另一个是基于对DOM的操作的。
效果:
蒲公英飘的动画:
进度条:

[以面向对象的形式重写,并使用严格模式,7.22日更新]
- /****************************RAFrame.js********************************/
- /*
- 1.依赖jquery
- 2.使用"use strict"严格模式
- */
- (function(){
- "use strict";
- //requestAnimationFrame属性的前缀
- var vendors = ['ms', 'moz', 'webkit', 'o'];
- for(var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) {
- windowwindow.requestAnimationFrame = window[vendors[x]+'RequestAnimationFrame'];
- windowwindow.cancelAnimationFrame = window[vendors[x]+'CancelAnimationFrame']
- || window[vendors[x]+'CancelRequestAnimationFrame'];
- }
- })();
- /*基类属性,构造函数*/
- function Animate(elementId,timeFrame,duration,propertyName,from,to,beginFrame,endFrame,changeStep){
- "use strict";
- this.element = elementId;
- this.timeFrame = timeFrame;
- this.startTime = 0;
- this.duration = duration;
- this.propertyName = propertyName;
- this.from = from;
- this.to = to;
- //当前帧属性值
- this.currPropValue = 0;
- //属性变化量
- this.changeRange = 0;
- //外部定义变化幅度
- this.changeStep = changeStep;
- //是否支持requestAnimationFrame
- this.isHasRAFrame = true;
- this.requestId = 0;
- //上一帧的启动时间
- this.lastTime = 0;
- //起始幻灯片
- this.beginFrame = beginFrame;
- //最终幻灯片
- this.endFrame = endFrame;
- }
- /*基类共享方法*/
- Animate.prototype = {
- init : function(){
- "use strict";
- var self = this;
- self.timeFrame = (typeof(self.timeFrame) == 'number') ? self.timeFrame : 800;// 默认0.8秒
- self.element = ( (typeof(self.element) == 'string')
- && (self.element != '') ) ? $('#' + self.element) : null;
- self.startTime = new Date;
- self.duration = (typeof(self.duration) == 'number') ? self.duration : 3000;//默认3秒
- self.from = (typeof(self.from) == 'number') ? self.from : 0;//默认0
- self.to = (typeof(self.to) == 'number') ? self.to : 300;//默认300
- self.propertyName = (typeof(self.propertyName) == 'string') ? self.propertyName : 'width';//默认width
- selfself.changeRange = self.to - self.from;
- if(window.requestAnimationFrame == undefined || window.requestAnimationFrame == null){
- self.isHasRAFrame = false;
- window.requestAnimationFrame = function( cb ) {
- //ie9-均未支持,可以先使用setTimeout模拟实现
- window.setTimeout( cb, 1000 / 60 );
- };
- }
- self.changeStep = (typeof(self.changeStep) == 'function') ? self.changeStep : function(){};
- if(self.element != null) {self.element.css(self.propertyName, self.from + 'px');};
- selfself.currPropValue = self.from;
- }
- // 动画启动
- ,startAnimate : function(type){
- "use strict";
- var self = this
- ,isContrisGo = (type == 'contrisGo');
- requestAnimationFrame(function(){
- var self = this
- ,isContrisGo = (type == 'contrisGo');
- return function(){
- if(isContrisGo){
- self.contrisGo();
- }else{ self.framesGo();}
- }
- }.call(this,self.isHasRAFrame));
- }
- // 属性切换模式
- ,contrisGo : function(currTime) {
- "use strict";
- var currTime = new Date
- ,self = this
- //当前帧与动画启动时刻的时间间隔
- ,tRange = currTime - self.startTime;
- //超过播放总时长,属性设为最终值
- if (tRange >= self.duration) {
- self.element.css(self.propertyName, self.to + 'px');
- return;
- }
- if(tRange < self.duration){
- selfself.currPropValue = self.from + self.changeRange * (tRange / self.duration);
- self.element.css(self.propertyName, self.currPropValue.toFixed() + 'px');
- requestAnimationFrame(function(){
- var self = this;
- return function(){
- self.contrisGo();
- }
- }.call(this));
- }
- }
- // 幻灯片切换模式
- ,framesGo : function(currTime){
- "use strict";
- var currTime = new Date
- ,self = this
- //当前帧与动画启动时刻的时间间隔
- ,tRange = currTime - self.lastTime;
- //属性变化
- if(tRange > 30){
- if(self.beginFrame <= self.endFrame){
- self.changeStep();
- self.lastTime = currTime;
- }else{
- self.stopAnimate();
- return;
- }
- }
- self.requestId = requestAnimationFrame(function(){
- var self = this;
- return function(){
- self.framesGo();
- }
- }.call(this));
- }
- ,stopAnimate : function() {
- "use strict";
- var self = this;
- if (self.requestId != 0){
- //ie9-均未支持
- if(window.cancelAnimationFrame != undefined){
- window.cancelAnimationFrame(self.requestId);
- self.requestId = 0;
- }
- }
- }
- }
- /*************外部调用,mine.js[7.22日更新]**************/
- var mine = {
- /*生成所有动画帧*/
- loadHtml : function(cb){
- "use strict";
- var n = 0
- ,self = this
- ,html = "";
- for(var z=0; z < 34; z++)
- {
- var num = z < 10 ? ("0"+z) : z;
- html += '<img class="img" src="images/tanpopo_00' + num + '.png" alt="" id="' + z +'" style="z-index:' + (34-z) + ';display:none'+'">';
- }
- $('#cnt').html(html);
- setTimeout(cb,2000);
- }
- /*动画一:蒲公英飘动*/
- , tanpopoMovie : function(){
- "use strict";
- var self = this
- ,changeStep = function(){
- if(this.beginFrame == 0){$('img').show();}
- $('#' + this.beginFrame).css('display','none');
- $('#' + this.beginFrame).hide();
- this.beginFrame++;
- };
- var fmsAnimate = new Animate('',800,2000,'',0,0,0,33,changeStep);
- fmsAnimate.init();
- fmsAnimate.startAnimate('framesGo');
- }
- }
- mine.loadHtml(mine.tanpopoMovie);
- /*动画二:进度条*/
- var cmAnimate = new Animate('progress',800,5000,'width',0,500,0,0);
- cmAnimate.init();
- cmAnimate.startAnimate('contrisGo');
- /************************************************************/
HTML:
- <!DOCTYPE HTML>
- <html>
- <head>
- <title>animationRequestFunction</title>
- <meta charset="UTF-8">
- </head>
- <body>
- <!--属性值修改的动画-->
- <div style="width: 500px; border: 1px solid black">
- <div id="progress" style="width: 0; height: 20px; background: none repeat scroll 0% 0% blue;"></div>
- </div>
- <!--DOM修改的动画-->
- <div id="cnt" style="background:url(images/bg01.jpg) no-repeat;">
- </div>
- <script type="text/javascript" src="js/jquery.js"></script>
- <script type="text/javascript" src="js/RAFrame.js"></script>
- <script type="text/javascript" src="js/mine.js"></script>
- </body>
- </html>
总结:经过面向对象的方式改造RAFrame.js ,可以让其中一个实例来管理一个动画,这样可以实现让多个动画同时播放,并且引入了严格模式来检查代码的健壮性,可以让代码质量写得更好,尤其是杜绝在类中抛出全局的变量等潜在风险的错误,在一些唔支持的浏览器采用了setTimeout(cb,1000/60)来代替requestAnimationFrame(cb)的调用,保证该类“Animate”在DeskTop的所有浏览器中依然能正常运行起来。
本文来源 我爱IT技术网 http://www.52ij.com/jishu/12021.html 转载请保留链接。
- 评论列表(网友评论仅供网友表达个人看法,并不表明本站同意其观点或证实其描述)
-
