11.6 精细地控制动画

虽然我们介绍了一些高级特性,但jQuery的效果模块还是有很多值得探索的地方。jQuery 1.8 重写了这个模块之后,又给高级开发人员提供了一些精细控制各种效果的手段,甚至可以让我们修改底层的动画引擎。比如,除了durationeasing选项之外,.animate()方法还提供了两个回调选项,让我们可以检视和修改动画的每一步:

  1. $('#mydiv').animate({
  2. height: '200px',
  3. width: '400px'
  4. }, {
  5. step: function(now, tween) {
  6. //监控高度和宽度,
  7. //调整补间属性
  8. },
  9. progress: function(animation, progress, remainingMs) {
  10. }
  11. });

在动画过程中,这里的setup()函数大约每13毫秒会针对每个动画属性被调用一次。这样,我们就可以调整tween对象的属性,比如终止值、缓动类型,或者根据传入的now参数中属性的当前值修改实际的动画属性。一个复杂一些的例子,就是可以在setup()函数中对两个运动的元素进行碰撞检测,然后调整各自的运动轨迹。

类似地,progress()函数在动画生命周期中也会被多次调用:

  • 它与setup()的区别在于,它只会在动画的每一步针对每个元素被调用一次,与多少属性产生动画效果无关;

  • 它提供了动画其他方面的调整选项,包括动画的承诺对象、进度(0到1之间的一个值)和动画剩余的毫秒数。

jQuery所有的动画都使用JavaScript的计时函数setTimeout()来重复调用函数。默认间隔时间为13毫秒,每次调用都会修改样式属性的值。不过,有些现代浏览器支持比setTimeout()更好的requestAnimationFrame()函数,使用这个函数不仅控制更精确(因此动画也更平顺),而且在移动设备上还能节省电量消耗。

我们知道,不管浏览器标签页是否活动,setTimeout()始终都不会停止运行。而requestAnimationFrame()函数则会在标签页不可见的时候暂停执行,因而更省电。领导重写jQuery动画的Corey Frang写了一个用requestAnimationFrame()替代setTimeout()的插件(只要浏览器支持就替换)。这个插件会修改$.fx对象的两个方法:.timer().stop(),免费下载地址是:https://github.com/gnarf/jquery-requestAnimationFrame

 对于动画而言,一般都应该使用 requestAnimationFrame() 替代 setTimeout()。不过,由于在代码中同时使用这两者可能会引发冲突,jQuery核心库并没有实现requestAnimationFrame()

jQuery动画系统最底层的方法是$.Animation()$.Tween()函数。这两个函数及其对应的对象可以用来调整动画的每个可能的方面。比如,可以使用$.Animation()来创建动画滤清器(prefilter)。像下面这个滤清器,就会在动画结束时根据传入.animate()方法的options对象中是否存在某个属性来执行一个特定的操作:

  1. $.Animation.prefilter(function(element, properties, options) {
  2. if (options.removeAfter) {
  3. this.done(function () {
  4. $(element).remove();
  5. });
  6. }
  7. });

有了这段代码,调用$('#my-div').fadeOut({removeAfter: true})就会在动画完成并淡出后自动删除DOM中的<div>