chaojidan

导航

第三十七课:动画的原理和设计

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

下一课,我们将通过源码来分析动画引擎的实现原理

 

 

 

加油!

posted on 2015-01-06 10:42  chaojidan  阅读(1519)  评论(0编辑  收藏  举报