若是你拿着一个疑问去找专业人士寻找答案,那么你的一个疑问会变成三个,由于他会用另外两个令你更加一头雾水的名词来解释你的这个疑问。javascript
我想这是大多数,包括我在内,IT人在学习过程当中碰到的最大问题。当你有一段代码或是一个概念不是很清楚,百度也好,Google也好,在论坛发问也好,给出的答案每每又会夹杂着更多你不懂得概念和令你头疼的代码。css
我亦是吃了一样的亏,痛定思痛,决定对animate方面作一些总结,但愿能给你们一些启发和帮助html
从一个实际应用谈起前端
今天不谈animate()、fadeIn()、fadeOut()、slideUp()、show()、hide()诸如此类的具体动画函数,而谈谈几个并不经常使用的,甚至说是有点风马牛不相及,但又十分十分重要的动画函数queue(),dequeue(),和stop()。java
先让咱们从一个简单的例子谈,假设有一个购物功能,在结帐以前,用户仍然能够把购物车里的删除至备选栏中(也许由于用户的资金不足,能够存储至下次购买)jquery
好,根据以上描述的需求,咱们抽象了如下的布局,"origin"模拟购物车,"goal"模拟备选栏,"object"模拟那个可能被删除的物品,而"change"按钮实现能够把物品从左右的交换功能chrome
同时咱们但愿当物品从左交换至右的过程当中,加入动画效果,咱们但愿是一个这样过程:在左侧先有一个hide()隐藏效果,告诉用户物品已经再也不购物篮中,而后前端用appendTo()把物品移动至右侧,在用一个show()效果告诉用户已经转移成功了。流程以下编程
(在左侧)object隐藏——>object从左侧转移到右侧——>object显现(在右侧)浏览器
因而很天然咱们得出了如下代码:网络
$(
'#object'
).hide(
'slow'
).appendTo($(
'#goal'
)).show(
'slow'
);
|
而且咱们将代码付诸于实践,以下所示:
本例完整代码:
$(
'#test-change'
).toggle(
function
(){
$(
'#test-object'
).hide(
'slow'
).appendTo($(
'#test-goal'
)).show(
'slow'
);
},
function
(){
$(
'#test-object'
).hide(
'slow'
).appendTo($(
'#test-origin'
)).show(
'slow'
);
|
当你运行以后会发现,结果并不如咱们但愿的那样。object会先发生转移,再隐藏,再出现:
object从左侧转移到右侧 ——>object隐藏(在右侧)——>object显现(在右侧)
因此问题是,明明是按咱们预约的顺序书写的,但结果却不如指望的那样,这是为何?
这也是我在本身项目中第一个接触queue()的实际例子,在jQuery的官方论坛发帖询问缘由后(原帖在这里),如下这段回答是关键
when you are using methods that animate content, those animations are added to what is called a queue, specifically the "fx" queue. normal jquery methods, such as prependTo(), are not added to the "fx" queue, therefore they get executed immediately instead of waiting till the previously added item in the queue is executed.
什么意思呢?也就是说,当你使用一系列的动画效果(如hide,show),这些动画函数都会被放进一个名为"fx"的队列中,而后在以先进先出的方式执行队列中的函数,而非动画函数,好比上面例子中的appendTo函数,则是不会进入这个队列中,而且先于动画函数的执行,也就是在"fx"先进先出,取出第一个函数以前,它就已经执行了。
因此在上面的例子中,咱们能够看到object被先转移到了右侧中,而后再隐藏再显现,也就是appendTo函数先执行于动画函数的结果
了解病根以后,咱们须要对症下药——说到底只是个顺序的问题,只要让appenTo后于hide先于show执行就万事大吉了。因而咱们想,可不能够也让appendTo函数加入队列而且位于hide和show之间?这样就能按顺序执行了
答案是确定了,虽然"fx"队列默认状况下是储备动画的函数,但加入了manipulation函数也没有什么不能够——准确来讲不只仅是manipulation函数,jQuery为咱们提供了queue()函数,来把你须要的某些代码插入到某个队列中。为何说某个?由于在后面的例子中咱们能够看到其实还能够自定义队列的。
咱们先把上面例子改为咱们但愿的效果,再根据代码来说解queue的方法
$(
'#object'
).hide(
'slow'
).queue(
function
(next){
$(
this
).appendTo($(
'#goal'
));
next();
}).show(
'slow'
);
|
其实看代码就一目了然。咱们能够这么理解(只是有助于理解它的功能,并不是它的实质),queue()就是不乖的,帮助插队的函数,你想让某个功能或某一系列功能插入几个动画之间,就把这一系列你想插入的功能函数放入queue()的函数体中,就向上面的代码同样,而参数"next"和next()则是保证再执行完这个插入的函数后,能继续能执行队列中的下一个动画函数,在上面的例子中也就是show()。
修改代码后,就能达到咱们要的效果了,以下所示:
本例完整代码:
$(
'#test-change1'
).toggle(
function
(){
$(
'#test-object1'
).hide(
'slow'
).queue(
function
(next){
$(
'#test-object1'
).appendTo($(
'#test-goal1'
));
next();
}).show(
'slow'
);
},
function
(){
$(
'#test-object1'
).hide(
'slow'
).queue(
function
(next){
$(
'#test-object1'
).appendTo($(
'#test-origin1'
));
next();
}).show(
'slow'
);
});
|
.queue()初探
接下来咱们正经谈谈queue函数
咱们仍是从一个简单的例子提及:
假如你要让一个黑色背景的小方块div,先收起(slideUp),在放下(SlideDown),背景再变成白色,语句应该怎么写?
吸收了上个例子的教训,相信没有会很天真的按顺序写出这样的语句了吧?
$(
'div'
).slideUp(
'slow'
).slideDown(
'slow'
).css({
"background"
:
"red"
});
|
应该怎么写呢?使用queue函数!brilliant!
$(
'div'
).slideUp(
'slow'
).slideDown(
'slow'
).queue(
function
(next){
$(
'#object'
).css({
"background"
:
"red"
});
next();
});
|
实际例子就不在页面上展现了,这是一段很简单的代码,应该能够想象获得吧。
在这里我想说明几个问题:
首先,jQuery官方在阐述.queue这个方法的时候有这么一句话颇有趣:
This feature is similar to providing a callback function with an animation method,
but does not require the callback to be given at the time the animation is performed.
咱们又要回到.queue()的函数定义,其实咱们如今这种在queue中加入函数的用法,官方给出的函数原型是:
queue( [ queueName ], callback( next ) )
也就是说咱们加入的函数实际上是一个关于队列的回调函数。也就是在队列结束以后,系统会自动为你调用你加入的函数。
插一句话,究竟什么是回调函数?百度一下,你就知道。返回结果的第一条就是百度百科关于“回调函数”的解释。可是正如本文章开头所说,它的确给了你很详细很详细的解释,但前提是你能消化那些C++专业词汇和代码……幸运的是个人Unix网络编程老师(嘿,一位来自北大的博士)曾经给过咱们一个很通俗的解释,本身定义,系统调用。回调函数的关键在于咱们没法预知它什么时候被调用。由于咱们只是定义了这么一个函数,可能通知系统在完成某一系列的动做后来调用它。
其实咱们能够这样考虑,若是把这个函数做为slideDown的回调函数效果不都是同样的吗?由于咱们最终想要的只是保证变色函数在slideDown以后执行,slideDown和queue的回调函数都能保证这种效果!look:
$(
'div'
).slideUp(
'slow'
).slideDown(
'slow'
,
function
(){
$(
'#object'
).css({
"background"
:
"red"
});
});
|
正是有殊途同归之妙。
还有一点须要注意的是.queue()中的next参数和next()能不能舍去其一或是?
咱们上面说到queue中的函数是回调函数,若是咱们稍稍对上上面的代码作一些修改,好比:
$(
'div'
).slideUp(
'slow'
).slideDown(
'slow'
).queue(
function
(next){
$(
'#object'
).css({
"background"
:
"red"
});
//next();
}).hide(
'slow'
);
|
一是我把next()语句注释掉了,二是但愿在变色之后再让方块隐藏起来。可是当你运行以后,发如今变色以后没法对方块执行隐藏。
要记住queue中的函数是回调函数呀,默认状况下只有动画队列执行完了,才会调用变色函数,既然动画队列都执行完了,哪里来的hide()?因此next()是保证在执行完此次队列后再次执行下一个动画函数
我曾经尝试过抛弃next参数而保留next()语句,这样的结果是能在现代浏览器(firefox,chrome之类)中运行,但没法在ie6中运行。因此,保留吧 。next和next()是jquery1.4中才开始出现的,而在以前使用的是.dequeue()函数,若是要将这节的例子改成使用dequeue(),以下:
$(
'#object'
).slideUp(
'slow'
).slideDown(
'slow'
).queue(
function
(){
$(
'#object'
).css({
"background"
:
"red"
});
$(
this
).dequeue();
});
|
自定义队列
我以前有提过其实能够不使用它默认的'fx'队列,这节就教你们怎么自定义一个属于本身的队列,很简单:
我想创建一个名为'custom'的队列,里面有一个能使黑色小方块改变背景颜色的方法,以下:
$(
"div"
).queue(
"custom"
,
function
(next) {
$(
'div'
).css({
'background'
:
'red'
});
next();
});
|
所见即所得——前面一个'custom'表明新队列的队列名(要是我也取'fx'会怎么样?我也不知道,有兴趣的朋友尝试以后能够留言告诉我结果,我也有兴趣会知道),后面仍然是回调函数,把你想执行的功能堆砌进去。
但就这段代码而已,待你真正添加进网页,而且尝试运行,会发现并不是“所见即所得”,压根就不会有任何效果。由于我故意省略了一段最最关键的语句……修改后的以下:
$(
"div"
).queue(
"custom"
,
function
(next) {
$(
'div'
).css({
'background'
:
'red'
});
next();
})
.dequeue(
"custom"
);
//this is the key
|
对,就是这句,.dequeue("custom")。通常对与dequeue()的定义是“删除队列中最顶部的函数,而且执行它”。我并不赞同用“删除”这个字眼,而是倾向于“取出”,其实这个函数的功能就好像是一个数据结构中队列的指针,待队列中前一个函数执行完后,取下一个队列最顶端的函数。
实战
OK,主要的几个知识点都介绍完了。或许你会问,咱们真的会用到这么复杂的动画操做吗呢?我相信大多数人士不会的,动画在网页中只是小小的点缀,可是当心驶得万年船。在这里我就照搬Cameron Mckay博客上的关于队列应用的例子
假设你要这么一个效果:让一个物体向上浮动2000毫秒(2秒),而且在前1000毫秒物体彻底不透明,而在后1000毫秒物体从彻底不透明变成彻底透明,为了解释的更清楚,给出了下面的这个时间轴表(假设物体开始在距容器顶部100px的位置,也就是top:100px;):
时间(毫秒) | 距顶端高度 | 不透明度 |
---|---|---|
0 | 100px | 1.0 |
500 | 90px | 1.0 |
1000 | 80px | 1.0 |
1500 | 70px | 0.5 |
2000 | 60px | 0.0 |
从时间轴表中咱们能够更清晰的看到咱们想要的效果,在这2000毫秒的时间内,物体的高度一致在均匀变化,逐渐减少,而不透明度在前1000毫秒始终保持为1.0,而在后1000毫秒才逐渐减少直至彻底为0。
若是咱们暂且只考虑向上浮动和透明效果,咱们可能会写出这样的语句:
$(
"#object"
).animate({opacity: 0, top:
"-=40"
}, {duration: 2000});
|
很遗憾,这样的语句只能让物体在总体2000毫秒中都处于逐渐向不透明转化的过程,也就是不能让它在前1000毫秒中保持100%不透明——因而咱们用queue来解决这个问题:
$(
"#object"
)
.delay(1000,
"fader"
)
.queue(
"fader"
,
function
(next) {
$(
this
).animate({opacity: 0},
{duration: 1000, queue:
false
});
next();
})
.dequeue(
"fader"
)
.animate({top:
"-=40"
}, {duration: 2000})
|
咱们先来看它的思路:把控制不透明度和控向上移动的动画分别存储在两个队列中,控制向上移动的队列按默认状况进行(在2000毫秒内完成),而不透明度的控制在1000毫秒内执行,但这个队列要晚于默认队列1000毫秒执行
再简单一点,就是:前1000毫秒,只有控制高度的“fx”队列执行,然后1000毫秒,控制不透明度的“fader”队列和控制高度的“fx”并行
首先准备两个队列,
一个是默认的"fx",存储高度变化动画:
.animate({top:
"-=40"
}, {duration: 2000})
|
用来另外一个是自定义的"fader"的队列,来存储不透明度变化的动画:
.animate({opacity: 0}, {duration: 1000, queue:
false
});
|
注意上面这段代码中的"queue:false",这是很关键的一句话,目的是让这个animate不进入默认的"fx"队列中
任何的动画效果都会进入"fx"队列中,即便你定义在.queue()中的动画也是同样,而且动画效果,务必会按顺序执行,好比说下面这段代码:
$(
'#object'
).slideUp(1000)<br> .slideDown(1000)<br> .animate({width:
'50px'
}, {duration: 1000});
|
运行后它只会按照顺序来执行,先收起,再放下,再把宽度收缩为50px
可是一旦我加入了"queue:false"这个参数:
$(
'#section3a'
).slideUp(1000)
.slideDown(1000)
.animate({width:
'50px'
}, {duration: 1000, queue:
false
});
|
你会发如今收缩放下的同时,object的宽度也在收缩
原本线性执行的slideUp,slideDown,animate,变成了animate和slideUp,slideDown并行:
运行结果以下
本例完整代码:
OK,咱们回过头来再看实战中的这个例子:
$(
"#object"
)
.delay(1000,
"fader"
)
.queue(
"fader"
,
function
(next) {
$(
this
).animate({opacity: 0},
{duration: 1000, queue:
false
});
next();
})
.dequeue(
"fader"
)
.animate({top:
"-=40"
}, {duration: 2000})
|
其实前三个语句(这里所说的语句以"."为区分标志),作了这么几件事:
定义一个名为fader的队列,专用于控制不透明度的改变——.queue()语句
让它1000毫秒后执行——.delay()延时函数,延时fader队列的执行时间;.dequeue执行fader队列。
而最后的.animate则是默认进行的,不用管它。一块儿来看看效果,左边的是正确的,右边的是错误的(可能在IE6中有布局错位的状况,由于是jQuery例子,时间有限,也就不追究css的错误了吧……):
本例完整代码:
好的,queue的主要功能就介绍到这里,下面还有点时间,介绍一些非主流功能:
获取队列长度
好比用队列名取得匹配元素的长度:
var
$queue=$(
"div"
).queue(
'fx'
);
|
很明显,就是取得队列名为'fx'的队列,若是想取得长度的话:
var
$length=$(
'div'
).queue(
'fx'
).length;
|
注意这里的队列长度只是匹配元素还未运行的队列长度,当动画运行完以后,队列长度会自动归为0,举下面一个例子:
function
animateT(){
$(
"#section2-div"
).slideToggle(
'3000'
)
.slideToggle(
'3000'
)
.hide(
'3000'
)
.show(
'3000'
)
.animate({left:
'+=200'
},2000)
.hide(
'3000'
)
.show(
'3000'
)
.animate({left:
'-=200'
},2000,animateT);
//在这轮动画结束的时候再调用本身,使动画无限循环下去
}
|
而后当点击按钮的时候显示队列的长度:
$(
"#section2-input"
).click(
function
(){
var
$queue=$(
"#section2-div"
).queue(
'fx'
);
$(
'#section2-h1'
).text($queue.length);
});
|
效果:
点击按钮就能够看见实时队列的长度
本例源码:
替换队列
queue还有一种用法是替换队列,就是自定义一个队列后,用自定义的队列替换元素原匹配的队列:
好比你给某个元素定义了两个队列:
$(
'div'
).queue(
'fx'
,
function
(){
$(
'div'
).slideDown(
'slow'
)
.slideUp(
'slow'
)
.animate({left:
'+=100'
},4000);
});
//定义fx
$(
'div'
).queue(
'fx2'
,
function
(){
$(
'div'
).slideDown(
'fast'
)
.slideUp(
'fast'
)
.animate({left:
'+=100'
},1000);
});
//定义fx2
|
这里定义了两个队列,一个是慢队列,也就是默认的'fx',另外一个是快队列'fx2'
当点击某个按钮时:
$(
'input'
).click(
function
(){
$(
'div'
).queue(
'fx'
,fx2);
});
|
很简单吧,明显用fx2替换了fx,固然这也不是当即替换,若是fx尚未执行完的话。除非你用stop()函数(咱们下节课介绍)。
总结
OK,今天对queue 的讲解就到这里,确定有不少疏漏的地方,但愿你们多多指证,上面的这些用法是我总结出来,应该算是比较主流的用法吧。若是还有一些我没有提到,或是有什么问题想交流,均可以留言给我。
参考的资料有jQuery官方文档说明 ,Cameron McKay的博客,《犀利开发jQuery》
下节课我打算向你们介绍stop()函数,也是我栽过跟头的地方。