如何在没有堆叠回调的情况下在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();
尝试类似的东西:
$( '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); }