How do I animate in jQuery without stacking callbacks?

后端 未结 7 1537
闹比i
闹比i 2020-12-08 05:37

Let\'s say I have three divs, and I\'d like each to animate once the previous one is done. Currently, I write this:

$(\'div1\').fadeOut(\'slow\', function()          


        
相关标签:
7条回答
  • 2020-12-08 05:56

    Use this:

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

    If you can give the <div>s a class:

    $('.forHide').each(function(index, value){
        $(this).delay(1000 * index).hide(1000);
    });​
    
    • The first element fades out after 1000 * 0 = right away with animation of one second.
    • The second element fades out after 1000 * 1 = One second with animation of one second.
    • The third element fades out after 1000 * 2 = Two seconds with animation of one second.
    • ...
    • ...
    • The n element fades in after 1000 * n = n seconds with animation of one second.

    Live DEMO

    0 讨论(0)
  • 2020-12-08 05:56

    Callback is a friend, dont push it away. There are ways to simplify them. Here is one of them

    $('div1').fadeOut('slow', div2)
    function div3() { $('div3').fadeOut('slow'); }
    function div2() { $('div2').fadeOut('slow', div3); }
    
    0 讨论(0)
  • 2020-12-08 06:00

    One way to do this would be to write your own helper function, like so:

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

    And use it like so:

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

    http://jsfiddle.net/JpNgv/

    0 讨论(0)
  • 2020-12-08 06:05

    If you're using a recent version of jQuery, use the animation promises:

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

    You can make it generic:

    $.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
    });
    

    Still a lot of function closures but that's the very nature of Javascript. However, it's much more natural and a lot more flexible using Deferreds/Promises since you avoid callbacks "inception".

    0 讨论(0)
  • 2020-12-08 06:09

    When ever completion functions or callbacks get nested too deep or code is getting repeated over and over again, I tend to think about a data table solution with a common function:

    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);
    

    And, if you wanted a different type of animation for some of the items, you could create a array of objects that describe what each successive animation is supposed to be. You could put as much detail in the array of objects as was needed. You can even intermix animations with other synchronous jQuery method calls like this:

    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);
    

    And, here's a working demo of this second option: http://jsfiddle.net/jfriend00/PEVEh/

    0 讨论(0)
  • 2020-12-08 06:13

    try something like:

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

    Adjust the timing as necessary

    0 讨论(0)
提交回复
热议问题