jQuery Animationen zeitversetzt mit callback(), delay() und queue()

jquery-animationen-zeitversetzt-mit-callback-delay-queue

jQuery Animationen sind einfach:

animation()

,

fadeToggle()

und

slideToggle()

erledigen die Arbeit schnell und unkompliziert. Es kann jedoch kompliziert werden, wenn man Animationen nacheinander abarbeiten möchte.
Generell werden Animationen „gleichzeitig“ ausgeführt, außer sie betreffen das selbe Objekt.
Verschiedene Objekte zeitverzögert zu animieren kann schon schwierig werden.

Ausgangssituation

2 Objekte mit je einer Animation:

$('#a').animate({
	width: '-=10px',
	height: '-=10px'
}, 2000, function() {
	// callback
});
$('#b').animate({
	width: '-=20px',
	height: '-=20px'
}, 2000, function() {
	// callback
});

2 Objekte, die gleichzeitig animiert werden obwohl der Code dies nicht vermuten lässt.

Demo

DEMO

Es gibt verschiedene Herangehensweisen für dieses Problem.

Lösung? callback()!

callback()

‚, oder auch

complete()

in der jQuery API Doc (Beispiel

animate()

), ist eine Funktion, die beim erfolgreichen Beenden einer Animation ausgeführt wird.
Ein Beispiel:

$('#b').animate({
	width: '-=10px',
	height: '-=10px'
}, 2000, function() {
	$('#a').animate({
		width: '-=20px',
		height: '-=20px'
	}, 2000, function() {
		// callback
	});
});

In der

callback()

Funktion können weitere Befehle folgen, die nach der beendeten Animation ausgeführt werden sollen.

Demo

DEMO

Alternative? delay()!

Den meisten jQuery Animationen kann man durch die Verwendung von

delay()

eine Pause anhängen. Die folgenden Befehle beziehen sich somit auf das selbe Objekt, sind aber zeitlich verzögert. Diese Methode ist nur auf Animationen anwendbar, die die Browser ‚effects queue‘ (auch ‚fx-queue‘ genannt) verwenden.

$('#a')
 .animate({
	width: '-=20px',
	height: '-=20px'
 }, 2000)
 .delay(2000)
 .fadeToggle()
 .delay(2000)
 .fadeToggle();
$('#b')
 .animate({
	width: '-=10px',
	height: '-=10px'
 }, 500)
 .delay(500)
 .slideToggle()
 .delay(500)
 .slideToggle();

Die verschiedenen Animationen sind nun zeitlich verzögert.

Demo

http://public.hannes-schurig.de/LocationMapDemo/map.php
Nach einem

objectA.delay()

Befehle folgen zu lassen, die auf ein anderes Objekt wirken sollen, geht meines Wissens nach nicht. Zwei Objekte zeitlich verzögert animieren geht damit also nicht. Dafür hilft aber die nächste Lösung!

Nun kommt es in jQuery jedoch oft vor, dass Befehle keine Animationen sind und somit weder ein callback besitzen noch ein delay verstehen. Solche Funktionen sind beispielsweise

html()

,

append()

,

css()

,

addClass()

oder

removeClass()

. Mit der folgenden Lösung lassen sich auch solche Funktionen zeitlich verzögert abarbeiten!

Lösung? queue()!

Die Funktion

queue()

erstellt eine ‚effects queue‘ Befehlskette, die beliebig gefüllt und dann abgearbeitet werden kann. Wie oben erklärt kann man das Ausführen von Befehlen innerhalb einer ‚effects queue‘ durch Anwendung von

delay()

zeitlich verzögern.

queue().delay()

ermöglicht es damit beliebige Befehle zeitlich verzögert auszuführen.

Der grobe Aufbau sieht wie folgt aus:

$(object).queue(function(param) {
	// Befehle
$(param).dequeue();
}).delay(1000).queue(function(param) {
	// Befehle nach 1 Sekunde Pause
$(param).dequeue();
});

Das Finale!

Hier das obrige Beispiel leicht angepasst: erst verändert sich Block #a in mehreren Schritten und erst danach Block #b:

$('#a').queue(function(next) {
	// 2 Sekunden Pause vor dem ersten Befehl
	$(next).dequeue();
}).delay(1000).queue(function(next) {
	$(this).css("background-color", "red");
	$(next).dequeue();
}).delay(1000).queue(function(next) {
	$(this).addClass("test");
	$(next).dequeue();
// block #b wird nun verändert:
}).delay(1000).queue(function(next) {
	$('#b').css("background-color", "red");
	$(next).dequeue();
}).delay(1000).queue(function(next) {
	$('#b').addClass("test");
	$(next).dequeue();
}).delay(1000).queue(function(next) {
	$('#b').animate({
		top: '+=150px'
	}, 1000);
	$(next).dequeue();
});
Demo

DEMO
BHAM! Zeitlich verzögerte Verarbeitung von beliebigen Befehlen von mehreren Objekten!

Update:
Mit der Javascript Funktion

setTimeout()

lassen sich auch extrem easy beliebige Elemente/Befehle zeitversetzt ausführen:

$("#signup-form input").addClass("success");
setTimeout(function (){
	$('#signup-carousel').carousel("next");
}, 2000);

Schande auf mein Haupt, dass ich das damals nicht schon kannte.

Die

queue()

Funktion kann man dabei direkt von dem Element aufrufen, dass animiert oder verändert werden soll, und innerhalb der

queue()

dann

$(this)

benutzen. Alternativ kann man auch ein globaleres Objekt benutzen, zum Beispiel

$(window).queue()

.

Damit sollte ich das Thema zeitverzögerte Animationen zu genüge beleuchtet haben. Bei meinem letzten Webprojekt spielte dieses Thema eine große Rolle und ich musste viel rumprobieren und testen bis ich die richtigen Einsatzgebiete und teils seltsamen Verhalten dieser Funktionen erkannt hatte. Wer sich also mit dem Thema auskennt, Fehler findet, weitere Möglichkeiten kennt, immer her damit!

2 Kommentare

  1. Hallo,
    Sie meinen 2sec Verzögerung bzgl. der Befehle des Selektors #b?

    Frage:
    Folgendes Programmschnitzel soll beim Click eine kleine Box von unselected auf selected schalten und umgekehrt. Macht es auch, allerdings schaltet es dann gleich wieder zurück. Das sieht man im Debugger.

    $(„.vacancyDay_“+cellText).click(function() {
    //$(this).toggleClass (‚unselected‘);

    if(! $(this).hasClass(’selected‘)) {
    $(this).addClass(„selected“);
    }
    //sleep (10);

    if($(this).hasClass(’selected‘)) {
    $(this).addClass(‚unselected‘);
    };
    });
    Durch probieren hatte ich einen sleep-Befehl zur Verzögerung der 2. if dazwischen geschaltet, dann funkt es, allerdings kommt dann ein Fehler im Debugger, weil JS den Befehl nicht kennt.
    Wie kann ich die erste if starten und erreichen, dass die Class selected noch nicht eingeschaltet ist, wenn die zwiete if aufgerufen wird?

    Mit toggle der gleiche Effekt.

    Haben Sie eine Idee oder einen anderen Vorschlag für das Problem?
    Danke!
    Paul

  2. Hallo Paul,
    du möchtest auf 1 Objekt 2 zeitversetzte Animationen anwenden. Genau darum geht’s in dem Artikel. Hat er dir nicht geholfen?
    Mal step by step: wenn du dir die Dokumentation zu toggleClass ansiehst, siehst du da keine callback/complete Funktion. Das heißt du nutzt am besten die queue Funktion.

    Der grobe Aufbau ist oben aufgezeigt:

    $(object).queue(function(param) {
        // Befehle
    $(param).dequeue();
    }).delay(1000).queue(function(param) {
        // Befehle nach 1 Sekunde Pause
    $(param).dequeue();
    });

    Nun setzt du beim ersten Kommentar dein erstes toggleClass ein, 10000(ms) Pause und dann im zweiten Block das zweite toggleClass.
    Nutze ruhig toggleClass, deine if Abfrage macht praktisch das gleiche.
    Probiere das mal aus, ich sitze hier gerade am Handy und kann nicht rumcoden. Ich denke nach dem Einsetzen läuft das.
    LG

Schreibe einen Kommentar