关于动画,你需要知道的

598 查看

这是我今年为新人设计的一门课程的文字精简版,完整的PPT可参考:http://matrix.h5jun.com/slide/show?id=117

简单的 JS 动画

在浏览器里,动画实现的基本原理非常简单明了,其实就是采用定时器改变显示元素的一些属性的过程。不管是JavaScript操作DOM的动画,还是CSS3动画,还是Canvas动画,或者SVG动画,区别只是使用的API、何种定时器,影响什么环境(DOM/Canvas/SVG/WebGL)。

基本动画

上面的例子里,我们使用了定时器 requestAnimationFrame,requestAnimationFrame 是浏览器专为渲染刷新设计的定时器接口,在早期版本的浏览器里,我们可以用 setTimeout 或者 setInterval 来代替它。定时器改变了方块元素的角度,每一次定时器触发我们就刷新并增加一次它的角度值,这样就产生了方块不断旋转的动态效果。

这就是我们需要的动画,几行原生JS代码就够了,是不是很简单呢?

事实上,上一节的动画不是最佳的实现方法。它存在着几个明显的改进点。

简单动画的问题

首先,requestAnimationFrame(或者setTimeout、setInterval等其他定时器)并不能保证严格在某个时间点被触发。还记得JavaScript的单线程非阻塞模型吧?如果requestAnimationFrame被其他任务给阻塞了,那么动画就会变慢:

“变慢”的动画

上面的动画,因为有其他的定时器耗时的操作,导致动画变慢。

其次,一个更加麻烦的问题是,上面的动画我们通过定时器给旋转角度增量的方式,或者说得更泛一点(暂时忽略前面那个定时器触发时间不确定的问题),我们通过定义速度的方式来改变动画,这会导致我们很难精确控制动画时间和动画的幅度。像前面这种匀速运动其实还好,如果做一些复杂的变速运动,按照我们的定义方式,我们本该设置的元素属性值将会类似于求积分,然而时间又不连贯。

正弦曲线运动

上面的动画由于时间不连贯绘制出来的曲线只能近似等于正弦曲线。

动画是“位移”关于“时间”的函数

动画,是位移关于时间的函数:(s = f(t))

所以,我们不该采用增量的方式来执行动画,为了更精确地控制动画,更合适的方式是将动画与时间联系起来:

动画与时间关联

动画通常情况下有终止时间,如果是循环动画,我们也可以看做特殊的——当动画达到终止时间之后,重新开始动画。因此,我们可以将动画时间归一(Normalize)表示:

动画时间归一化表示

我们可以用时间来控制动画:

用时间来控制动画周期精确在1秒

让滑块在2秒内向右匀速移动200px

我们可以将通过时间控制动画与前面的简单增量的办法做一个对比:

时间 V.S. 增量

时间 增量
幅度控制
时间控制 X
幅度控制
不延迟 X
不掉帧 X

变速运动

变速运动可以模拟一些物理效果、曲线运动,以及其他的一些非均匀变化的特效。

匀加速运动

加速度恒定,速度从0开始随时间增加而均匀增加。

  • (t = T cdot p)
  • (s_t = S cdot p ^ {2} = (frac{S}{T^2}) t^2 )
  • (v = frac{2S}{T^2} cdot t = frac{2Sp}{T})
  • (a = frac{2S}{T^2} )

通过推导可以得到匀减速运动的位移时间公式:(s_t = Sp^2)

滑块在2秒内向右匀加速移动200px,速度从0开始