最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - jQuery adding functions to the animation queue - Stack Overflow

programmeradmin1浏览0评论

The problem is that when I try doing multiple animations they all happen the same time.
Is there any way to have animations go one after another without using callbacks?

Here's what I want to do:

$('#a1').click(function() { $('#div1').hide(3000); });
$('#a2').click(function() { $('#div2').hide(3000); });
$('#a3').click(function() { $('#div3').show(3000); });

If you click on #a1 and then click on #a2 then #a3 before the first animation completes then it shouldn't start right away but instead wait until the animation queue is empty then start the next one.

Take this demo for example

I want to be able to click a1 then a2 then a3 one after the another and first have it hide the first div completely, then the second completely, and then show the third.

My example is overly simple and while this can be done with callbacks, my real problem can't so callbacks aren't an option.

In essence, if you click all three the animation should complete in 9 seconds.

This DEMO should alert ('took around 9 seconds to complete')

The problem is that when I try doing multiple animations they all happen the same time.
Is there any way to have animations go one after another without using callbacks?

Here's what I want to do:

$('#a1').click(function() { $('#div1').hide(3000); });
$('#a2').click(function() { $('#div2').hide(3000); });
$('#a3').click(function() { $('#div3').show(3000); });

If you click on #a1 and then click on #a2 then #a3 before the first animation completes then it shouldn't start right away but instead wait until the animation queue is empty then start the next one.

Take this demo for example

I want to be able to click a1 then a2 then a3 one after the another and first have it hide the first div completely, then the second completely, and then show the third.

My example is overly simple and while this can be done with callbacks, my real problem can't so callbacks aren't an option.

In essence, if you click all three the animation should complete in 9 seconds.

This DEMO should alert ('took around 9 seconds to complete')

Share Improve this question edited Jun 4, 2012 at 0:43 qwertymk asked Jun 3, 2012 at 18:21 qwertymkqwertymk 35.3k30 gold badges124 silver badges184 bronze badges 1
  • In your real problem, do you have to take care of the animations after the click handlers have already been assigned or do you have control over the definition of those handler functions being passed as arguments to the click method? – Ed I Commented Jun 15, 2012 at 20:53
Add a comment  | 

7 Answers 7

Reset to default 9 +50

Use .queue() on a common jQuery object:

var q = $({}); // this could also be a common parent, e.g. $('body')
$('#a1').click(function() {
    q.queue(function(next) {
        $('#div1').hide(3000, next);
    });
    return false;
});
$('#a2').click(function() {
    q.queue(function(next) {
        $('#div2').hide(3000, next);
    });
    return false;
});
$('#a3').click(function() {
    q.queue(function(next) {
        $('#div3').show(3000, next);
    });
    return false;
});​

Demo

Use .promise() to sidestep callbacks on show and hide:

The .promise() method returns a dynamically generated Promise that is resolved once all actions of a certain type bound to the collection, queued or not, have ended.

By default, type is "fx", which means the returned Promise is resolved when all animations of the selected elements have completed

Use .queue() to limit the number of animations resolved per promise (See also jsFiddle):

var promises = $({});

$('#a1').click(function() {
    promises.queue(function(next) {
        $('div').promise().done(function() {
            $('#div1').hide(3000);
            next();
        });
    });
    return false;
});
$('#a2').click(function() {
    promises.queue(function(next) {
        $('div').promise().done(function() {
            $('#div2').hide(3000);
            next();
        });
    });
    return false;
});
$('#a3').click(function() {
    promises.queue(function(next) {
        $('div').promise().done(function() {
            $('#div3').show(3000);
            next();
        });
    });
    return false;
});

Try to create some array with queue, and check if there is something in it, as callback for animation, and run it again if there is. I've played with your example a little.

check it out:

http://jsfiddle.net/acrashik/nqh6x/6/

var queue = {
    q: [],
    run: function(elem, type, time, recall) {
        if (queue.isRunning && !recall) {
            console.log('pushed: ' + elem + type + time);            
            queue.q.push({elem:elem, type:type, time:time});
        } else {
            console.log('running:' + elem);
            queue.isRunning = true;
            if (type=='hide') {
                $(elem).hide(time, function(){
                    queue.recall();
                })
            } else {
                $(elem).show(time, function(){
                    queue.recall();
                })             
            }
        }                    
    },
    recall: function(){
        console.log(queue.q.length);                    
        if (queue.q.length > 0) {
            queue.run(queue.q[0].elem, queue.q[0].type, queue.q[0].time, true);
            queue.q = queue.q.splice(1,queue.q.length);
        } else {
            queue.isRunning = false;
            queue.q = [];
        }
    },            
    isRunning: false
}
$('#a1').click(function() { queue.run('#div1','hide',2200) });
$('#a2').click(function() { queue.run('#div2','hide',2200) });
$('#a3').click(function() { queue.run('#div3','show',2200) });

I would use the animate() function as it comes with a complete function which is called when the animation finishes http://api.jquery.com/animate/.

So to use the jQuery doc example:

$('#clickme').click(function() {
  $('#book').animate({
   opacity: 0.25,
   left: '+=50',
   height: 'toggle'
}, 5000, function() {
// Animation complete this is where you call the next animation...
  });
});

function another_animation () {
  $('xyz').animate({
   opacity: 0.25,
   left: '+=50',
}5000, function() {
// Animation complete this is where you call the next animation

I think that this is the cleanest way...

You could do something like this:

(function(){
    var col=(function(){
        var i=1;
        return function(n){alert("you clicked link nr " + n + ", total clicks: "+i++)};
    })();
    $('#a1').click(function(){col(1)});
    $('#a2').click(function(){col(2)});
    $('#a3').click(function(){col(3)});
})();

Im not gona write the entire code for you but that should give you a good idea of how to do it. Also none of the variables or functions are accessible from the global scope or any other.

Add stop() before the animation:

$('#a1').click(function() { $('#div1').stop().hide(3000); });
$('#a2').click(function() { $('#div2').stop().hide(3000); });
$('#a3').click(function() { $('#div3').stop().show(3000); });

Use this $(element).promise().done(function () {...})

In your case

$('#a1').click(function () {
    $('#div1').hide(3000);
});
$('#a2').click(function () {
    $("#div1").promise().done(function () {
        $('#div2').hide(3000);
    });
});
$('#a3').click(function () {
    $("#div2").promise().done(function () {
        $('#div3').hide(3000);
    });
});

The next animation will be performed only when the previous animation on selected element is complete.

发布评论

评论列表(0)

  1. 暂无评论