大熊君学习html5系列之------requestAnimationFrame(实现动画的另一种方案)

一,开篇分析

Hi,大家好!大熊君又和大家见面了,(*^__^*) 嘻嘻……,这系列文章主要是学习Html5相关的知识点,以学习API知识点为入口,由浅入深的引入实例,

让大家一步一步的体会"h5"能够做什么,以及在实际项目中如何去合理的运用达到使用自如,完美驾驭O(∩_∩)O~,好了,废话不多说,直接进入今天的主题,

今天主要讲的是“requestAnimationFrame API”及在客户端浏览器中的作用,并且会引入一个实际的例子做为讲解的原型范例,让我们先来看看“requestAnimationFrame API”:

  其实在web开发中,我们实现动画效果的可选方案已经很多了:

  1,你可以用CSS3的animattion+keyframes。

  2,你也可以用css3的transition。

  3,你还可以用通过在canvas上作图来实现动画,也可以借助jQuery动画相关的API方便地实现。

  4,你还可以使用最原始的“window.setTimout()”或者“window.setInterval()”通过不断更新元素的状态位置等来实现动画,前提是画面的更新频率要达到每秒60次才能让肉眼看到流畅的动画效果。

  5,哈哈哈!现在又多了一种实现动画的方案,那就是还在草案当中的“window.requestAnimationFrame()”方法。

    

  requestAnimationFrame是什么?

    在浏览器动画程序中,我们通常使用一个定时器来循环每隔几毫秒移动目标物体一次,来让它动起来。如今有一个好消息,浏览器开发商们决定:“嗨,为什么我们不在浏览器里提供这样一个API呢,

这样一来我们可以为用户优化他们的动画。”所以,这个requestAnimationFrame()函数就是针对动画效果的API,你可以把它用在DOM上的风格变化或画布动画好或WebGL中。

  使用requestAnimationFrame有什么好处?

    浏览器可以优化并行的动画动作,更合理的重新排列动作序列,并把能够合并的动作放在一个渲染周期内完成,从而呈现出更流畅的动画效果。

比如,通过requestAnimationFrame(),JS动画能够和CSS动画/变换或SVG SMIL动画同步发生。另外,如果在一个浏览器标签页里运行一个动画,当这个标签页不可见时,

浏览器会暂停它,这会减少CPU,内存的压力,节省电池电量。

  requestAnimationFrame的用法

   先来看一个简单的小栗子:

   模拟一个进度条动画,初始div宽度为1px,在step函数中将进度加1然后再更新到div宽度上,在进度达到100之前,一直重复这一过程。

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

window.requestAnimationFrame = window.requestAnimationFrame || window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame || window.msRequestAnimationFrame;
var start = null;
var ele = document.getElementById("test");
var progress = 0;

function step(timestamp) {
    progress += 1;
    ele.style.width = progress + "%";
    ele.innerHTML=progress + "%";
    if (progress < 100) {
        requestAnimationFrame(step);
    }
}
requestAnimationFrame(step);
document.getElementById("run").addEventListener("click", function() {
    ele.style.width = "1px";
    progress = 0;
    requestAnimationFrame(step);
}, false);

  

  

  运行效果如下:

  

二,深入requestAnimationFrame

  我们对动画的要求苛刻吗?

  对于时间要求苛刻的动画,永远不要使用 setTimeout() 或 setInterval()。

  时间间隔设置为 1000/60 毫秒,这相当于大约每秒 60 帧。这个数字是我对最佳帧速率的最佳估值,它可能不是一个很好的值,但是,因为 setInterval() 和 setTimeout() 完全不了解动画,所以由我指定帧速率。

浏览器肯定比我更了解何时绘制下一个动画帧,因此,如果改为由浏览器指定帧速率,会产生更好的结果。

  使用 setTimeout 和 setInterval() 甚至有一个更严重的缺陷。虽然您传递以毫秒为单位指定的这些方法的时间间隔,但这些方法没有精确到毫秒。事实上,根据 HTML 规范,

这些方法(为了节约资源)慷慨地拉长您指定的时间间隔。

  使用 setTimeout 和 setInterval() 甚至有一个更严重的缺陷。虽然您传递以毫秒为单位指定的这些方法的时间间隔,但这些方法没有精确到毫秒;事实上,根据 HTML 规范,这些方法(为了节约资源)慷慨地拉长您指定的时间间隔。

为了避免这些缺陷,对于时间要求苛刻的动画,不应使用 setTimeout() 和 setInterval(),而是应该使用 ”requestAnimationFrame()“

  我们要做两件实际的事:

  (1),兼容处理,不同浏览器厂商肯定内部实现有区别

window.requestAnimFrame = (function(){
  return  window.requestAnimationFrame       ||
	window.webkitRequestAnimationFrame ||
	window.mozRequestAnimationFrame    ||
	function( callback ){
	window.setTimeout(callback, 1000 / 60);
	};
})();

  

  (2),另一种方式实现

  

(function() {
    var lastTime = 0;
    var vendors = [‘webkit‘, ‘moz‘];
    for(var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) {
        window.requestAnimationFrame = window[vendors[x]+‘RequestAnimationFrame‘];
        window.cancelAnimationFrame =
          window[vendors[x]+‘CancelAnimationFrame‘] || window[vendors[x]+‘CancelRequestAnimationFrame‘];
    }

    if (!window.requestAnimationFrame)
        window.requestAnimationFrame = function(callback, element) {
            var currTime = new Date().getTime();
            var timeToCall = Math.max(0, 16 - (currTime - lastTime));
            var id = window.setTimeout(function() { callback(currTime + timeToCall); },
              timeToCall);
            lastTime = currTime + timeToCall;
            return id;
        };

    if (!window.cancelAnimationFrame)
        window.cancelAnimationFrame = function(id) {
            clearTimeout(id);
        };
}());

  

三,相关分享

  (1),Tween.js 

  1 var Tween = {
  2     Linear: function(t, b, c, d) { return c*t/d + b; },
  3     Quad: {
  4         easeIn: function(t, b, c, d) {
  5             return c * (t /= d) * t + b;
  6         },
  7         easeOut: function(t, b, c, d) {
  8             return -c *(t /= d)*(t-2) + b;
  9         },
 10         easeInOut: function(t, b, c, d) {
 11             if ((t /= d / 2) < 1) return c / 2 * t * t + b;
 12             return -c / 2 * ((--t) * (t-2) - 1) + b;
 13         }
 14     },
 15     Cubic: {
 16         easeIn: function(t, b, c, d) {
 17             return c * (t /= d) * t * t + b;
 18         },
 19         easeOut: function(t, b, c, d) {
 20             return c * ((t = t/d - 1) * t * t + 1) + b;
 21         },
 22         easeInOut: function(t, b, c, d) {
 23             if ((t /= d / 2) < 1) return c / 2 * t * t*t + b;
 24             return c / 2*((t -= 2) * t * t + 2) + b;
 25         }
 26     },
 27     Quart: {
 28         easeIn: function(t, b, c, d) {
 29             return c * (t /= d) * t * t*t + b;
 30         },
 31         easeOut: function(t, b, c, d) {
 32             return -c * ((t = t/d - 1) * t * t*t - 1) + b;
 33         },
 34         easeInOut: function(t, b, c, d) {
 35             if ((t /= d / 2) < 1) return c / 2 * t * t * t * t + b;
 36             return -c / 2 * ((t -= 2) * t * t*t - 2) + b;
 37         }
 38     },
 39     Quint: {
 40         easeIn: function(t, b, c, d) {
 41             return c * (t /= d) * t * t * t * t + b;
 42         },
 43         easeOut: function(t, b, c, d) {
 44             return c * ((t = t/d - 1) * t * t * t * t + 1) + b;
 45         },
 46         easeInOut: function(t, b, c, d) {
 47             if ((t /= d / 2) < 1) return c / 2 * t * t * t * t * t + b;
 48             return c / 2*((t -= 2) * t * t * t * t + 2) + b;
 49         }
 50     },
 51     Sine: {
 52         easeIn: function(t, b, c, d) {
 53             return -c * Math.cos(t/d * (Math.PI/2)) + c + b;
 54         },
 55         easeOut: function(t, b, c, d) {
 56             return c * Math.sin(t/d * (Math.PI/2)) + b;
 57         },
 58         easeInOut: function(t, b, c, d) {
 59             return -c / 2 * (Math.cos(Math.PI * t/d) - 1) + b;
 60         }
 61     },
 62     Expo: {
 63         easeIn: function(t, b, c, d) {
 64             return (t==0) ? b : c * Math.pow(2, 10 * (t/d - 1)) + b;
 65         },
 66         easeOut: function(t, b, c, d) {
 67             return (t==d) ? b + c : c * (-Math.pow(2, -10 * t/d) + 1) + b;
 68         },
 69         easeInOut: function(t, b, c, d) {
 70             if (t==0) return b;
 71             if (t==d) return b+c;
 72             if ((t /= d / 2) < 1) return c / 2 * Math.pow(2, 10 * (t - 1)) + b;
 73             return c / 2 * (-Math.pow(2, -10 * --t) + 2) + b;
 74         }
 75     },
 76     Circ: {
 77         easeIn: function(t, b, c, d) {
 78             return -c * (Math.sqrt(1 - (t /= d) * t) - 1) + b;
 79         },
 80         easeOut: function(t, b, c, d) {
 81             return c * Math.sqrt(1 - (t = t/d - 1) * t) + b;
 82         },
 83         easeInOut: function(t, b, c, d) {
 84             if ((t /= d / 2) < 1) return -c / 2 * (Math.sqrt(1 - t * t) - 1) + b;
 85             return c / 2 * (Math.sqrt(1 - (t -= 2) * t) + 1) + b;
 86         }
 87     },
 88     Elastic: {
 89         easeIn: function(t, b, c, d, a, p) {
 90             var s;
 91             if (t==0) return b;
 92             if ((t /= d) == 1) return b + c;
 93             if (typeof p == "undefined") p = d * .3;
 94             if (!a || a < Math.abs(c)) {
 95                 s = p / 4;
 96                 a = c;
 97             } else {
 98                 s = p / (2 * Math.PI) * Math.asin(c / a);
 99             }
100             return -(a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
101         },
102         easeOut: function(t, b, c, d, a, p) {
103             var s;
104             if (t==0) return b;
105             if ((t /= d) == 1) return b + c;
106             if (typeof p == "undefined") p = d * .3;
107             if (!a || a < Math.abs(c)) {
108                 a = c;
109                 s = p / 4;
110             } else {
111                 s = p/(2*Math.PI) * Math.asin(c/a);
112             }
113             return (a * Math.pow(2, -10 * t) * Math.sin((t * d - s) * (2 * Math.PI) / p) + c + b);
114         },
115         easeInOut: function(t, b, c, d, a, p) {
116             var s;
117             if (t==0) return b;
118             if ((t /= d / 2) == 2) return b+c;
119             if (typeof p == "undefined") p = d * (.3 * 1.5);
120             if (!a || a < Math.abs(c)) {
121                 a = c;
122                 s = p / 4;
123             } else {
124                 s = p / (2  *Math.PI) * Math.asin(c / a);
125             }
126             if (t < 1) return -.5 * (a * Math.pow(2, 10* (t -=1 )) * Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
127             return a * Math.pow(2, -10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p ) * .5 + c + b;
128         }
129     },
130     Back: {
131         easeIn: function(t, b, c, d, s) {
132             if (typeof s == "undefined") s = 1.70158;
133             return c * (t /= d) * t * ((s + 1) * t - s) + b;
134         },
135         easeOut: function(t, b, c, d, s) {
136             if (typeof s == "undefined") s = 1.70158;
137             return c * ((t = t/d - 1) * t * ((s + 1) * t + s) + 1) + b;
138         },
139         easeInOut: function(t, b, c, d, s) {
140             if (typeof s == "undefined") s = 1.70158;
141             if ((t /= d / 2) < 1) return c / 2 * (t * t * (((s *= (1.525)) + 1) * t - s)) + b;
142             return c / 2*((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2) + b;
143         }
144     },
145     Bounce: {
146         easeIn: function(t, b, c, d) {
147             return c - Tween.Bounce.easeOut(d-t, 0, c, d) + b;
148         },
149         easeOut: function(t, b, c, d) {
150             if ((t /= d) < (1 / 2.75)) {
151                 return c * (7.5625 * t * t) + b;
152             } else if (t < (2 / 2.75)) {
153                 return c * (7.5625 * (t -= (1.5 / 2.75)) * t + .75) + b;
154             } else if (t < (2.5 / 2.75)) {
155                 return c * (7.5625 * (t -= (2.25 / 2.75)) * t + .9375) + b;
156             } else {
157                 return c * (7.5625 * (t -= (2.625 / 2.75)) * t + .984375) + b;
158             }
159         },
160         easeInOut: function(t, b, c, d) {
161             if (t < d / 2) {
162                 return Tween.Bounce.easeIn(t * 2, 0, c, d) * .5 + b;
163             } else {
164                 return Tween.Bounce.easeOut(t * 2 - d, 0, c, d) * .5 + c * .5 + b;
165             }
166         }
167     }
168 }
169 Math.tween = Tween;

  (2),ball.js

 1 var ball = $("ball"), shadow = $("shadow");
 2 var objBall = {};
 3 var shadowWithBall = function(top) {
 4     // 0 ~ 500
 5     var top = top || parseInt(ball.css("top")),
 6     scale = 1 + (500 - top) / 300;
 7     opacity = 1 - (500 - top) / 300;
 8     if (opacity < 0) opacity = 0;
 9     shadow.css("opacity", opacity)
10     .css("WebkitTransform", "scale("+ [scale, scale].join(",") +")")
11     .css("transform", "scale("+ [scale, scale].join(",") +")");
12 }, funFall = function() {
13     var start = 0, during = 100;
14     var _run = function() {
15         start++;
16         var top = Tween.Bounce.easeOut(start, objBall.top, 500 - objBall.top, during);
17         ball.css("top", top);
18         shadowWithBall(top);
19         if (start < during) requestAnimationFrame(_run);
20     };
21     _run();
22 };
23 ball.bind("mousedown", function(event) {
24     objBall.pageY = event.pageY;
25     objBall.flagFollow = true;
26 });
27 $(document).bind("mousemove", function(event) {
28     if (objBall.flagFollow) {
29         var pageY = event.pageY;
30         objBall.top = 500 - (objBall.pageY - pageY);
31         if (objBall.top < 0) {
32             objBall.top = 0;
33         } else if (objBall.top > 500) {
34             objBall.top = 500;
35         }
36         //cosnole.log(objBall.top);
37         ball.css("top", objBall.top);
38         shadowWithBall(objBall.top);
39     }
40 });
41 $(document).bind("mouseup", function(event) {
42     if (objBall.flagFollow) funFall();
43     objBall.flagFollow = false;
44 });

  效果如下:  

    

(四),最后总结

  (1),理解requestAnimationFrame Api的使用方式以及具体实例中使用的目的是为了解决哪些问题。

  (2),requestAnimationFrame 与 之前“setTimeout setInterval”的不同之处在哪。

  (3),熟练使用requestAnimationFrame对象,不断实践与重构文章中的栗子。

                   哈哈哈,本篇结束,未完待续,希望和大家多多交流够沟通,共同进步。。。。。。呼呼呼……(*^__^*)    

时间: 2024-10-09 20:46:40

大熊君学习html5系列之------requestAnimationFrame(实现动画的另一种方案)的相关文章

大熊君学习html5系列之------Online &amp;&amp; Offline(在线状态检测)

一,开篇分析 Hi,大家好,给大家拜个晚年!大熊君又和大家见面了,(*^__^*) 嘻嘻……,这系列文章主要是学习Html5相关的知识点,以学习API知识点为入口,由浅入深的引入实例,让大家一步一步的体会"h5"能够做什么,以及在实际项目中如何去合理的运用达到使用自如,完美驾驭O(∩_∩)O~,好了,废话不多说,直接进入今天的主题, online,offline 事件用来监测浏览器处于在线或离线状态.HTML5提出的离线存储,web应用程序可以在不连接互联网的情况下满足用户的部分需求,

大熊君学习html5系列之------History API(SPA单页应用的必备------重构完结版)

一,开篇分析 Hi,大家好!大熊君又和大家见面了,(*^__^*) 嘻嘻……,这系列文章主要是学习Html5相关的知识点,以学习API知识点为入口,由浅入深的引入实例, 让大家一步一步的体会"h5"能够做什么,以及在实际项目中如何去合理的运用达到使用自如,完美驾驭O(∩_∩)O~,好了,废话不多说,直接进入今天的主题, 今天主要讲的是对昨天文章中的代码进行重构,并且相应的美化了一下前台UI界面,如下图所示的效果: 哈哈哈酷吧!继续让咱们做个简单的回顾: 为了提高Web页面的响应速度,越

大熊君学习html5系列之------History API(SPA单页应用的必备)

一,开篇分析 Hi,大家好!大熊君又和大家见面了,(*^__^*) 嘻嘻……,这系列文章主要是学习Html5相关的知识点,以学习API知识点为入口,由浅入深的引入实例, 让大家一步一步的体会"h5"能够做什么,以及在实际项目中如何去合理的运用达到使用自如,完美驾驭O(∩_∩)O~,好了,废话不多说,直接进入今天的主题, 今天主要讲的是“History API”及在单页应用中的作用,并且会引入一个实际的例子做为讲解的原型范例,先来看看“History API”: 为了提高Web页面的响应

大熊君学习html5系列之------XHR2(XMLHttpRequest Level 2)

一,开篇分析 Hi,大家好!大熊君又和大家见面了,(*^__^*) 嘻嘻……,这系列文章主要是学习Html5相关的知识点,以学习API知识点为入口,由浅入深的引入实例, 让大家一步一步的体会"h5"能够做什么,以及在实际项目中如何去合理的运用达到使用自如,完美驾驭O(∩_∩)O~,好了,废话不多说,直接进入今天的主题, 今天主要讲的是“XMLHttpRequest Level 2 API”及在客户端浏览器中的作用,并且会引入一个实际的例子做为讲解的原型范例,让我们先来看看“XHR AP

大熊君学习html5系列之------WebStorage(客户端轻量级存储方案)

一,开篇分析 Hi,大家好!大熊君又和大家见面了,(*^__^*) 嘻嘻……,这系列文章主要是学习Html5相关的知识点,以学习API知识点为入口,由浅入深的引入实例, 让大家一步一步的体会"h5"能够做什么,以及在实际项目中如何去合理的运用达到使用自如,完美驾驭O(∩_∩)O~,好了,废话不多说,直接进入今天的主题, 今天主要讲的是“WebStorage API”及在客户端浏览器中的作用,并且会引入一个实际的例子做为讲解的原型范例,让我们先来看看“WebStorage API”: H

&quot;MindManager&quot;学习iOS系列之&quot;CAAnimation-核心动画&quot;详解,让你的应用“动”起来。

"MindManager"学习iOS系列之"CAAnimation-核心动画"详解,思维导图内展示了CAAnimation-核心动画的大多数基本功能和知识,每个part都有代码讲解,展示出CAAnimation-核心动画的清晰轮廓,编者提供了"JPG"."SWF"."PDF"."Word"."Mmap"格式的源文件供给使用.注意:JPG格式仅为图片总览,SWF格式使用

从0開始学习 GitHub 系列之「07.GitHub 常见的几种操作」

之前写了一个 GitHub 系列,反响非常不错,突然发现居然还落下点东西没写,前段时间 GitHub 也改版了,借此机会补充下. 我们都说开源社区最大的魅力是人人多能够參与进去,发挥众人的力量,让一个项目更完好.更强壮.那么肯定有人疑问,我自己眼下还没有能力开源一个项目,可是想一起參与到别的开源项目中.该怎么操作呢?那么今天,就来给大家一起介绍下 GitHub 上的一些常见的操作,看完之后你就知道方法了. 我们姑且以 Square 公司开源的 Retrofit 为例来介绍. 打开链接: http

cocos2d-x学习笔记(二)序列帧动画实现的几种方法

一.cocos2d-x帮助文档中关于动画帧动画的实现有两种方法: 手动添加序列帧到Animation类 使用文件初始化Animation类 这里我就不列出来,大家可以看下官方文档 http://www.cocos.com/doc/article/index?type=cocos2d-x&url=/doc/cocos-docs-master/manual/framework/native/v3/frame-animation/zh.md 二.有些时候我们需要从plist取出指定的几个图片(而不是全

大熊君JavaScript插件化开发------(实战篇之DXJ UI ------ ProcessBar)

一,开篇分析 Hi,大家好!大熊君又和大家见面了,还记得前两篇文章吗.主要讲述了以“jQuery的方式如何开发插件”,以及过程化设计与面向对象思想设计相结合的方式是 如何设计一个插件的,两种方式各有利弊取长补短,本系列文章是以学习为导向的,具体场景大家自己定夺使用方式.那么今天从这篇文章开始,我们就以实例 的方式带着大家由浅入深的开发属于自己的插件库.嘿嘿嘿,废话少说,进入正题.直接上实际效果图: 大家看到了吧,这是一个进度条插件,在我们日常开发中,有时我们会有一个装载数据的进度提示,如果无任何