开发者

Using jQuery delay() with separate elements

I want to fake a simple animation on page load by sequentially revealing several pngs, each appearing instantly but with unique, precisely timed delay before the next one. Using the latest version of jQuery (1.4.2 at writing), which provides a delay method. My first (braindead) impulse was:

$('#image1').show('fast').delay(800);
$('#image2').show('fast').delay(1200);
$('#image3').show('fast');

Of course all come up simultaneously. jQuery doc examples refer to a single item being chained, not handling multiple items. OK... try again using nested callbacks from show():

$('#image1').show('fast', function() {
    $('#image2').show('fast', function() {      
        $('#image3').show('fast', function() {      
        });
    });
});

Looks ugly (imagine doing 10, also wonder what processor hit would be) but hey, it works sequentially! Without delay though. So... chain delay() after show() using a callback function from it (not even sure if it supports one):

$('#image1').show('fast').delay(800, function() {
    $('#image2').show('fast').delay(1200, function() {      
        $('#image3').show('fast');
    });
});

Hm. Opposite result of what I thought might happen: the callback works, but still no delay. So... should I be using some combination of queue and delay instead of nested callbacks? jQuery doc examples for queue again only use one element for exampl开发者_运维问答e. Guessing this would involve using a custom queue, but am uncertain how to implement this. Or maybe I'm missing a simple way? (For a simple problem!)


You could simplify it if they're right there together:

function showNext(img) {
  //show, find next image, repeat, when next doesn't find anything, it'll stop
  img.show('fast', function() { showNext($(this).next('[id^=image]')); });
}
//Call the first image to start the chain
showNext($("#image1"));

If they are further apart, just adjust that .next() selector to how to find the next image, or you could assign a class to them all, etc...however you can traverse to the next one works.


Wild guess here, but what about

$('#image1').show('fast', function() {
    $('#image2').delay(800).show('fast', function() {      
        $('#image3').delay(1200).show('fast', function() {      
        });
    });
});


There's probably a trendy way to do this directly with jQuery but I'd be tempted to do it with a simple array and a plain timeout mechanism.

var toShow = ["image1", "image2", "image3", ... ], index = 0;
setTimeout(function() {
  $('#' + toShow[index++]).show('fast');
  if (index >= toShow.length) return;
  setTimeout(arguments.callee, 1000);
}, 1000);

You could put your "delay" values into the array too, if they're not supposed to be the same all the time:

var toShow = [ {img: "image1", delay: 800}, {img: "image2", delay: 1200}, ... ],
  index = 0;
setTimeout(function() {
  $('#' + toShow[index].img).show('fast');
  if (index >= toShow.length) return;
  setTimeout(arguments.callee, toShow[index].delay);
}, toShow[0].delay);

edit this is fun :-) If you wanted to, you could build the image array as a jQuery object — in other words, you could drop the images into your HTML and then "find" them with a jQuery selector. As to the delay values, well, if you wanted to make the delay a per-image thing you could code that into the image class name either with the jQuery "metadata" plugin or with a simpler hack if you don't need anything that elaborate for other stuff:

var toShow = $('img.showMeSlowly'), index = 0, getDelay = function(img) {
  var delay = 1000;
  $(img).attr('class').replace(/.*\bdelay:(\d+)\b.*/, function(_, ds) {
    delay = parseInt(ds, 10);
  });
  return delay;
};

setTimeout(function() {
  toShow.eq(index++).show('fast');
  if (index >= toShow.length) return;
  setTimeout(arguments.callee, getDelay(toShow.get(index)));
}, getDelay(toShow.get(0)));


Using a queue is pretty straightforward:

var imgs = ['#image1','#image2','#image3',...];

function showNext() {
  var img = imgs.shift();
  if (img) $(img).show('fast', showNext);  
}

showNext(); // start


I am a bit amazed about the weired answers given here. The question is a bit older, but I guess others will still search and find this, so let's go:

First of all, delay() does not accept a callback function. If you want to delay any action, you have to put the delay() in the dot-notation chain in front of the action:

$('#image1').delay(800).show('fast');

This will wait for 0.8 seconds and then reveal the image quickly (duration 'fast' = 0.2 seconds).

Second, if you have multiple actions that you want to run simultaneously, you simply write them one after the other:

$('#image1').show('fast');
$('#image2').show('fast');

This way they will all start at the same time, so the above code will play the fade-in animation of #image1 and #image2 in parallel!

If you want to start several animations with different delays, you combine both strategies and simply do:

$('#image1').show('slow');
$('#image2').delay(1000).show('slow');
$('#image3').delay(1600).show('slow');
$('#image4').delay(2000).show('slow');

Depending on the delays and the durations, this allows you to play the animations with gaps in-between each (2 starts with a delay after 1 has finished), consecutively (3 starts when 2 just finished, as duration 'slow' is 600 ms) and delayed but with overlap (4 starts while 3 is still running). All you have to do is adapt your delays and your durations. This is actually the answer to your question and the most versatile method to do what you want.

A word about the callback function: This is available with show(), animate() and several other methods (but not with delay, as you tried it!) and is mainly needed if you want to do more complex things after an animation has finished. Be careful though: When your selector matches multiple elements, e.g. $('#image1, #image2'), the callback will be called multiple(!) times - once for each element in your set. This can lead to very unexpected results (quick hint: look for information about jQuery's when()/then() methods to avoid that).

Finally and for the sake of completeness, if you simply want to run multiple animations on the same element(s) - one animation after the other and with possible delays in-between - you can simply do...

$('#image1').show('fast').hide('slow').delay(500).show('slow').hide('fast');

This will show the image quickly, then hide it slowly, then wait for half a second, then show it slowly and then hide it quickly.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜