当前位置: 代码迷 >> Web前端 >> jQuery动画高级用法(下)
  详细解决方案

jQuery动画高级用法(下)

热度:268   发布时间:2012-11-16 14:12:15.0
jQuery动画高级用法(上)
jQuery动画高级用法(上)――详解animation中的.queue()函数   如果你拿着一个疑问去找专业人士寻找答案,那么你的一个疑问会变成三个,因为他会用另外两个令你更加一头雾水的名词来解释你的这个疑问。

      我想这是大多数,包括我在内,IT人在学习过程中碰到的最大问题。当你有一段代码或是一个概念不是很清楚,百度也好,Google也好,在论坛发问也好,给出的答案往往又会夹杂着更多你不懂得概念和令你头疼的代码。

  我亦是吃了同样的亏,痛定思痛,决定对animate方面做一些总结,希望能给大家一些启发和帮助

从一个实际应用谈起

  今天不谈animate()、fadeIn()、fadeOut()、slideUp()、show()、hide()诸如此类的具体动画函数,而谈谈几个并不常用的,甚至说是有点风马牛不相及,但又十分十分重要的动画函数queue(),dequeue(),和stop()。

     先让我们从一个简单的例子谈,假设有一个购物功能,在结账之前,用户仍然可以把购物车里的删除至备选栏中(也许因为用户的资金不足,可以存储至下次购买)

  好,根据以上描述的需求,我们抽象了以下的布局,"origin"模拟购物车,"goal"模拟备选栏,"object"模拟那个可能被删除的物品,而"change"按钮实现可以把物品从左右的交换功能

  同时我们希望当物品从左交换至右的过程中,加入动画效果,我们希望是一个这样过程:在左侧先有一个hide()隐藏效果,告诉用户物品已经不再购物篮中,然后前端用appendTo()把物品移动至右侧,在用一个show()效果告诉用户已经转移成功了。流程如下

(在左侧)object隐藏――>object从左侧转移到右侧――>object显现(在右侧)

于是很自然我们得出了以下代码:

$('#object').hide('slow').appendTo($('#goal')).show('slow');


并且我们将代码付诸于实践,如下所示:

origin objectgoal
本例完整代码:

   $('#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()。

修改代码后,就能达到我们要的效果了,如下所示:

container objectgoal
本例完整代码:


   $('#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();
     });




  相关解决方案