11.6 精细地控制动画
虽然我们介绍了一些高级特性,但jQuery的效果模块还是有很多值得探索的地方。jQuery 1.8 重写了这个模块之后,又给高级开发人员提供了一些精细控制各种效果的手段,甚至可以让我们修改底层的动画引擎。比如,除了duration
和easing
选项之外,.animate()
方法还提供了两个回调选项,让我们可以检视和修改动画的每一步:
$('#mydiv').animate({
height: '200px',
width: '400px'
}, {
step: function(now, tween) {
//监控高度和宽度,
//调整补间属性
},
progress: function(animation, progress, remainingMs) {
}
});
在动画过程中,这里的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
对象中是否存在某个属性来执行一个特定的操作:
$.Animation.prefilter(function(element, properties, options) {
if (options.removeAfter) {
this.done(function () {
$(element).remove();
});
}
});
有了这段代码,调用$('#my-div').fadeOut({removeAfter: true})
就会在动画完成并淡出后自动删除DOM中的<div>
。