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


    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{   //父元素

        800px;  height: 100px; background:#e8e8ff; position:relative;

      }

      #move{    //移动的元素,也就是做动画的元素

        position:absolute;  left:0px; 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对象,比如:{800px;height:500px},它代表元素,将从原始的100和height:100变成800和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({300},2000).animate({left:300},2000); 前两秒,宽度从100变成300,然后,后两秒,left从0到300.具体请看:http://www.cnblogs.com/chaojidan/p/4183687.html

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

    加油!

  • 相关阅读:
    ZOJ 3949 Edge to the Root( 树形dp)
    CCF201812-3 CIDR合并
    CF700E E. Cool Slogans
    BZOJ4552: [Tjoi2016&Heoi2016]排序
    BZOJ3238: [Ahoi2013]差异
    BZOJ4566: [Haoi2016]找相同字符
    Codeforces Global Round 1 A~F
    (HDU)1555-- How many days? (多少天)
    (HDU)1491-- Octorber 21st (校庆)
    (HDU)1465-- 不容易系列之一
  • 原文地址:https://www.cnblogs.com/chaojidan/p/4204209.html
Copyright © 2020-2023  润新知