如何在没有堆叠回调的情况下在jQuery中制作动画?

假设我有三个div,并且我希望每个div都完成前一个动画。 目前,我写这个:

$('div1').fadeOut('slow', function() { $('div2').fadeOut('slow', function() { $('div3').fadeOut('slow'); }); }); 

这是丑陋的,但可管理。

现在想象一下,我有10种不同的动画需要在不同的元素上一个接一个地发生。 突然间,代码变得如此笨重,以至于管理起来非常困难……

这是我想要做的伪代码:

 $('div1').fadeOut('slow' { delay_next_function_until_done: true } ); $('div2').fadeOut('slow' { delay_next_function_until_done: true } ); $('div3').animate({ top: 500 }, 1000 ); 

我该如何实现这一目标?

如果您使用的是最新版本的jQuery,请使用动画承诺:

 $('div1').fadeOut('slow').promise().pipe(function() { return $('div2').fadeOut('slow'); }).pipe(function() { return $('div3').animate({ top: 500 }, 1000 ); }); 

你可以把它变成通用的:

 $.chain = function() { var promise = $.Deferred().resolve().promise(); jQuery.each( arguments, function() { promise = promise.pipe( this ); }); return promise; }; var animations = $.chain(function() { return $('div1').fadeOut('slow'); }, function() { return $('div2').fadeOut('slow'); }, function() { return $('div3').animate({ top: 500 }, 1000 ); }); $.when( animations ).done(function() { // ALL ANIMATIONS HAVE BEEN DONE IN SEQUENCE }); 

仍然有很多function关闭,但这是Javascript的本质。 但是,使用Deferreds / Promises更自然,更灵活,因为您可以避免回调“开始”。

我这样做,使用这种方法,您可以根据需要放置所有div,只添加或删除列表var中的元素,也可以重新排序它们,您不必担心延迟时间。

 var list = [ '#div1', '#div2', '...' ]; var i = 0; function fade(cb) { if (i < list.length) { $(list[i]).fadeOut('slow', function() { i++; fade(cb); }); } else { cb && cb(); } } fade(); 

您还可以在流程结束时添加回调

 fade(function(){alert('end')}); 

演示

当完成函数或回调嵌套太深或代码反复重复时,我倾向于考虑具有常见函数的数据表解决方案:

 function fadeSequence(list) { var index = 0; function next() { if (index < list.length) { $(list[index++]).fadeOut(next); } next(); } var fades = ["div1", "div2", "div3", "div4", "div5"]; fadeSequence(fades); 

而且,如果你想为某些项目设置不同类型的动画,你可以创建一个对象数组来描述每个连续动画应该是什么。 您可以根据需要在对象数组中添加尽可能多的细节。 您甚至可以将动画与其他同步jQuery方法调用混合使用,如下所示:

 function runSequence(list) { var index = 0; function next() { var item, obj, args; if (index < list.length) { item = list[index++]; obj = $(item.sel); args = item.args.slice(0); if (item.sync) { obj[item.type].apply(obj, args); setTimeout(next, 1); } else { args.push(next); obj[item.type].apply(obj, args); } } } next(); } // sequence of animation commands to run, one after the other var commands = [ {sel: "#div2", type: "animate", args: [{ width: 300}, 1000]}, {sel: "#div2", type: "animate", args: [{ width: 25}, 1000]}, {sel: "#div2", type: "fadeOut", args: ["slow"]}, {sel: "#div3", type: "animate", args: [{ height: 300}, 1000]}, {sel: "#div3", type: "animate", args: [{ height: 25}, 1000]}, {sel: "#div3", type: "fadeOut", args: ["slow"]}, {sel: "#div4", type: "fadeOut", args: ["slow"]}, {sel: "#div1", type: "fadeOut", args: ["slow"]}, {sel: "#div5", type: "css", args: ["position", "absolute"], sync: true}, {sel: "#div5", type: "animate", args: [{ top: 500}, 1000]} ]; runSequence(commands); 

而且,这是第二个选项的工作演示: http : //jsfiddle.net/jfriend00/PEVEh/

一种方法是编写自己的辅助函数,如下所示:

 $.fn.sequentialFade = function() { if(this.length > 0) { var $set = $(this); $set.eq(0).fadeOut(function() { $set.slice(1).sequentialFade(); }); } } 

并像这样使用它:

 $('.div1, .div2. .div3').sequentialFade(); 

http://jsfiddle.net/JpNgv/

尝试类似的东西:

 $( 'div1' ).fadeOut(); $( 'div2' ).delay( 500 ).fadeOut(); $( 'div3' ).delay( 1000 ).fadeOut(); 

根据需要调整时间

用这个:

 $('#div1, #div2, #div3').each(function(index){ $(this).delay(1000 * index).hide(1000); }); 

如果你能给

sa类:

 $('.forHide').each(function(index, value){ $(this).delay(1000 * index).hide(1000); });​ 
  • 第一个元素在1000 * 0 =之后逐渐淡出,动画为一秒。
  • 第二个元素在1000 * 1 = 1秒后淡出,动画为1秒。
  • 第一个元素在1000 * 2 = 两秒后淡出,动画为一秒。
  • n元素在1000 * n = n秒后淡入,动画为1秒。

现场演示

回调是朋友,不要把它推开。 有一些方法可以简化它们。 这是其中之一

 $('div1').fadeOut('slow', div2) function div3() { $('div3').fadeOut('slow'); } function div2() { $('div2').fadeOut('slow', div3); }