js里面最简单的动画原理:在setTimeout或setInterval定时器中,每隔20-30ms改变元素的样式,于是就有了动画。比如:改变宽高,就叫缩放;改变坐标,就叫做位移;改变坐标轴,就叫旋转;改变透明度,就叫做淡入淡出。
css3中有一个transform样式,它的值可以是rotate()旋转,skew()扭曲,scale()缩放,translate()位移,matrix()矩阵。这里不仅支持2D的操作,也支持3D的操作。
我们先举一个小小的例子,来实现一个方块的移动,达到动画的效果。
让一个方块动起来,其实就是改变这个方块的位置。在css中对应元素的left和top样式。要想用left和top,我们还需要让元素相对定位或绝对定位。通常的做法是父元素相对定位,称为包含块,子元素绝对定位。只有定位了,left和top才是可计算的像素值。首先,我们需要取到元素的原始位置,然后让用户传入结束位置,起始位置与结束位置之间的距离,就是我们要一点点操作的变量。动画还涉及到时间,也就是动画执行的总时间,这里的意思就是方块从起始位置到结束位置,总共花了多长时间。动画最重要的一点就是每次变动的相隔时间,这个通常由引擎决定,当然也可以自己设定,我们一般叫它fps。
fps通俗的讲就是一秒内更新多少次画面。一般来说,一秒更新30张画左右,就会有动画的效果。也就是说,一张画停留大概33毫秒(1000/30)。
现在,我们用代码来实现上面的这个例子。我们假设从原始位置到目的位置,总共需要2秒钟(动画总时间),fps为30帧(一秒内更新30张画)。
<style type="text/css">
#parent{ //父元素
width:800px; height: 100px; background:#e8e8ff; position:relative;
}
#move{ //移动的元素,也就是做动画的元素
position:absolute; left:0px; width:100px; height:100px; background:#a9ea00;
}
</style>
<script>
var el = document.getElementById("move");
var parent = document.getElementById("parent");
var distance = parent.offsetWidth - el.offsetWidth; //需要移动的距离
var begin = 0; //move元素的开始位置
var end = begin + distance; //move元素的目的位置
var fps = 30;
var interval = 1000/fps; //每相隔多少毫秒刷新一次,也就是一张画停留多少毫秒,然后切换下一张画。
var duration = 2000;
var times = duration /interval; //这个动画,总共要刷新多少次,也就是说总共有多少张画要显示。
var step = distance / times; //这个动画,每次刷新,要移动多少距离。
el.onclick = function(){
var now = new Date();
var id = setInterval(function(){
if(begin>=end){
el.style.left = end + "px";
clearInterval(id);
}else{
begin + = step; //每次刷新,元素需要移动的距离
el.style.left = begin + "px";
}
},interval); //每相隔interval就刷新一次画面,也就是移动元素
}
</script>
上例中,我们使用了最简单的累加来实现。现在我们改写一下,加入进度这个变量,让其具有广泛性。
el.onclick = function(){
var now = new Date();
var id = setInterval(function(){
var t = new Date() - now; //当前时间减去动画开始的时间,也就是动画执行了多少毫秒
if(t>=duration){ //如果动画执行的时间大于或等于总时间,就停止
el.style.left = end + "px";
clearInterval(id);
}else{
var per = t/duration; //当前动画执行的进度
el.style.left = begin + per*distance + "px"; //当前的进度乘以总距离,就得到它当前的位置
}
},interval); //每相隔interval就刷新一次画面,也就是移动元素
}
如果我们随意能够控制per这个数值,那么就能轻易的实现加速和减速。于是,人们发明了缓动公式,缓动公式可以让我们很轻松的模拟现实中的加速,减速,弹簧等效果。
现在的缓动公式的命名是有一定的规律的:基本函数:linear(easeNone)匀速,easeIn加速,easeOut减速,easeInOut先加速再减速。
高阶函数与三角函数:Sine表示由三角函数实现,Quad是二次方,Cubic是三次方,Quart是四次方,Quint是五次方,Circ使用开平方根的Math.sqrt,Expo使用开立方根的Math.pow,Elastic则是结合三角函数与开立三方根的初级弹簧效果,Back则使用一个1.70158常数来计算回退效果,Bounce则是高级弹簧效果。
由于,我们一般只使用基本函数,因此熟悉基本函数就OK了,至于高阶函数,了解就行。实现这些缓动公式的库:AS库,jquery.easing.js,mootools库等。
我们根据上面的例子,把缓动公式加入进去:
var bounce = function(per){ //缓动公式
if(per < (1 / 2.75) ){
return (7.5625*per*per);
}else if(per < (2/2.75)){
return (7.5625 * (per-=(1.5/2.75)) * per + 0.75);
}
else if(per < (2.5/2.75)){
return (7.5625 * (per-=(2.25/2.75)) * per + 0.9375);
}else{
return (7.5625 * (per-=(2.625/2.75)) * per + 0.984375);
}
}
el.onclick = function(){
var now = new Date();
var id = setInterval(function(){
var per = (new Date() - now)/duration; //当前时间减去动画开始的时间,也就是动画执行了多少毫秒,除以动画执行的总时间,就是当前动画执行的进度(0-1之间)
if(per>=1){ //如果动画执行的时间大于或等于总时间,就停止
el.style.left = end + "px";
clearInterval(id);
}else{
el.style.left = begin + bounce(per)*distance + "px"; //当前的进度(这里的进度是通过缓动公式生成的,因此具有缓动公式的效果)乘以总距离,就得到了它当前的位置,然后把元素移动到当前位置。
}
},interval); //每相隔interval就刷新一次画面,也就是移动元素
}
上面的动画,你会发现,当你点击它时,方块到终点后还弹回来,再过去,又弹回来,渐渐的停止。以上的缓动公式不用理解,知道它是个缓动公式就行,关键是掌握缓动公式在动画中的应用。
最后,我们来看一下jQuery的动画API的设计:
animate(properties, duration , easing , complete)
animate(properties, options)
第一种方式,后面的三个参数是可选的,第一个参数是一个属性集的json对象,比如:{width:800px;height:500px},它代表元素,将从原始的width:100和height:100变成width:800和width:500,出现动画效果,至于动画的时长,变换规则(缓动公式),通过后面的参数设置,如果后面没有设置参数,那么将使用jQuery里面默认的值。第二个参数代表动画的时长,第三个参数代表动画使用什么样的缓动公式,第四个参数代表动画执行结束后,执行的回调方法。
第二种方式,第一个参数跟第一种方式是一样的,它的第二个参数是一个json对象,里面大概是这样的{animation-duration:2,animation-timing-function:ease-in-out},通过options这个对象来设置动画的时长,缓动公式等。它跟CSS3的动画设置非常相似。举个例子:
.animate { //这个animate类名加在上面的那个方块元素中,这个类名也可以是其他名字,比如:.move,只要设置的是那个方块元素就OK了。
animation-duration:3s;
animation-name:slidein;
animation-timing-function:ease-in-out;
animation-fill-mode:forwards;
}
@keyframes slidein { //设置这个动画的初始位置和目的位置
from{ left:0%; background:white; }
to{ left:700px; background: red; }
}
上面的动画,是通过css3来设置的,它总共有两个样式设置,第一个样式规则,用于描述动画所需的时长,缓动公式,动画结束后保留的状态,以及动画的名字。
第二个样式规则,设置动画slidein的关键帧,这里只设置了两个关键帧,实际上我们可以插入更多(通过50%,80%),最开始与结束的帧可以通过from(0%)和to(100%)命名,其实当你用js去获取这个值时,from和to会自动转换成百分数,0%,100%。结束的帧是最重要的,我们必须设置,它对应于jQuery的animate方法的第一个参数,至于最开始的帧,css3的方式,浏览器会自动计算,jQuery的animate方式,animate方法中会用js获取。
jQuery的animate的第二个参数options就对应第一个样式规则。
jQuery的animate方法,里面使用的是一个叫做queue队列的数据结构,目的让作用于同一个元素的动画进行排队,先处理完这个动画,再处理后一个,比如:
$(this).animate({width:300},2000).animate({left:300},2000); 前两秒,宽度从100变成300,然后,后两秒,left从0到300.具体请看:http://www.cnblogs.com/chaojidan/p/4183687.html
下一课,我们将通过源码来分析动画引擎的实现原理
加油!