在博文jQuery代码分析之一中偶介绍了下animation的实现机制,怎样实现属性值的渐变?那么如果我们需要在一个元素上做链式animation时,jQuery是如何处理的呢?例如,有如下示范代码:
$("#div1").slideDown().fadeOut();
这里面涉及到的技术就是偶将在这篇文章中讲到的fn.queue。首先还是看下API定义
描述:定义将在匹配元素上执行的一组函数。
queue([queueName], newQueue)
queueName:queue的名字,默认值为fx,默认的fx queue也是jquery在做animation时默认存放回调函数的队列。
newQueue:用一组新的函数队列取代当前queue,如果传入空数组[],那就是把这个queue清空。
queue([queueName], callback(next))
callback(next):往队列里插入一个回调函数,注意它可以接受一个参数next,这个next是一个函数对象,其定义如下
next = function() {
jQuery.dequeue( elem, type );
};
因此我们可以实现一个这样的回调函数
$("#test").queue(function(next) {
// Do some stuff...
next();
});
因为fn.queue/dequeue是依赖于jQuery.queue/dequeue的,所以我们准备看看jQuery.queue/dequeue的实现。
jQuery.queue()的实现代码很直观,就是函数功能的翻译。那我们看看jQuery.dequeue()的实现,稍微复杂一点
dequeue: function( elem, type ) {
type = type || "fx";
var queue = jQuery.queue( elem, type ),
startLength = queue.length,
fn = queue.shift(),
hooks = jQuery._queueHooks( elem, type ),
next = function() {
jQuery.dequeue( elem, type );
};
// If the fx queue is dequeued, always remove the progress sentinel
if ( fn === "inprogress" ) {
fn = queue.shift();
startLength--;
}
if ( fn ) {
// Add a progress sentinel to prevent the fx queue from being
// automatically dequeued
if ( type === "fx" ) {
queue.unshift( "inprogress" );
}
// clear up the last queue stop function
delete hooks.stop;
fn.call( elem, next, hooks );
}
if ( !startLength && hooks ) {
hooks.empty.fire();
}
}
上面这段代码有几个地方需要另外解释下。
1. _queueHooks()是个什么东东?因为它涉及到Deferred object,所以我们先暂时把它理解作。。。Deferred object会在下一篇博文中介绍。
2. 为啥要在队列前面插入一个"inprogress"?
原来fn.queue是在jQuery.queue的基础上又做了一件事,
var queue = jQuery.queue( this, type, data );
// ensure a hooks for this queue
jQuery._queueHooks( this, type );
if ( type === "fx" && queue[0] !== "inprogress" ) {
jQuery.dequeue( this, type );
}
如果队列首不是"inprogress"的话,那就要执行出队列操作。然而每次调用jQuery.dequeue是,都会在队列首部插入一个"inprogress",这就保证了jQuery.dequeue只会被fn.queue调用一次,后面的调用会因为queue[0]=="inprogress"而不执行jQuery.dequeue(this, type)。那有人会问,怎样保证queue首部只有一个"inprogress"呢?答案很简单,jQuery.dequeue在做出对操作时,会检查队首是否为"inprogress",如果是的话,就会继续出对,直到遇到一个非"inprogress"值(通常为一个回调函数),或者直到队列为空。
关于queue与dequeue的用法可以参考 jQuery中queue和dequeue的用法