Früher gab es nur eine Möglichkeit, eine zeitgesteuerte Schleife in JavaScript zu machen: setInterval(). Wenn Sie etwas ziemlich schnell wiederholen mussten (aber nicht so schnell wie möglich, wie eine for-Schleife), würden Sie das verwenden. Zum Zwecke der Animation ist das Ziel sechzig „Frames“ pro Sekunde, um reibungslos zu erscheinen, also würden Sie eine Schleife wie diese ausführen:
setInterval(function() {
// animiate something
}, 1000/60);
Dafür gibt es jetzt eine bessere Alternative. Paul Irish führte requestAnimationFrame vor über zwei Jahren ein. Ich habe dem nicht viel hinzuzufügen, ich hatte es nur noch nie wirklich benutzt und jetzt habe ich es, also dachte ich, ich helfe, die Nachricht zu verbreiten und schreibe über seine grundlegende Verwendung.
Warum besser?
Wie Paul erklärte
- Der Browser kann es optimieren, sodass Animationen flüssiger werden
- Animationen in inaktiven Tabs stoppen, sodass die CPU sich entspannen kann
- Batteriefreundlicher
Das einfachste Beispiel
function repeatOften() {
// Do whatever
requestAnimationFrame(repeatOften);
}
requestAnimationFrame(repeatOften);
Rufen Sie es einmal auf, um es zu starten, und Ihre Funktion ruft sich selbst rekursiv auf.
Starten und Stoppen
requestAnimationFrame gibt eine ID zurück, mit der Sie sie abbrechen können, ähnlich wie setTimeout oder setInterval. jQuery wurde hier nur verwendet, um eine einfache Animation zu demonstrieren und Ereignisse zu binden.
var globalID;
function repeatOften() {
$("<div />").appendTo("body");
globalID = requestAnimationFrame(repeatOften);
}
$("#start").on("click", function() {
globalID = requestAnimationFrame(repeatOften);
});
$("#stop").on("click", function() {
cancelAnimationFrame(globalID);
});
Beispiel davon
Check out this Pen!
Browser-Unterstützung
Siehe die Kann ich benutzen… Tabellen.
Die einzigen bemerkenswerten Probleme sind IE 9-, iOS 5- und Android. Aber eigentlich kein Problem, denn
Polyfill
Wie viele schicke Web-Features ist es schön, sie zu verwenden, wenn verfügbar, und auf etwas zurückzufallen, das funktioniert, wenn Sie es nicht können. Wahrscheinlich am besten, einfach auf diesen Gist zu verweisen. Fügen Sie diesen Block buchstäblich irgendwo ein, bevor Sie requestAnimationFrame oder cancelAnimationFrame verwenden.
Wenn Sie dies verwenden, können Sie requestAnimationFrame buchstäblich in jedem Browser verwenden.
Etwas komplexeres Beispiel
Ich habe davon erfahren, als ich eine dämliche kleine Demo gemacht habe, um Canvas besser zu lernen
Siehe den Pen Super Simple requestAnimationFrame Thing von Chris Coyier (@chriscoyier) auf CodePen.
Was tatsächlich komplexer wäre, wären mehrere Animationen, die gleichzeitig mit dieser Methode laufen (das fällt immer noch gut zurück). Fühlen Sie sich frei, etwas von dieser Güte in den Kommentaren zu verlinken, wenn Sie Beispiele kennen.
Sie können mein „Einfachstes mögliches Beispiel“ noch einfacher machen :)
Ja, der Einfachheit halber funktioniert es, aber ich würde nicht empfehlen, eine Animation so zu starten, da sie im exakt gleichen Moment gerendert wird, in dem sie aufgerufen wird, und nicht, wenn der Browser tatsächlich frei ist, sodass der Sinn von requestAnimationFrame verfehlt wird.
Oder **noch einfacher**
Klicken Sie beim ersten Beispiel mehrmals auf Start. :P
Oh, ja, und wir müssen immer noch Vendor-Präfixe dafür verwenden, aber es ist eine großartige Methode. Das Web entwickelt sich ständig weiter…
Das oben erwähnte Polyfill kümmert sich darum und noch ein paar kleine Dinge, um sicherzustellen, dass alles perfekt funktioniert (wie das Zurückfallen auf setTimeout und die Handhabung von Abbrüchen).
Hier ist ein Fork des ersten Beispiels, aber ich habe Code hinzugefügt, damit es nicht fehlschlägt, wenn Sie mehrmals auf Schaltflächen klicken.
http://cdpn.io/cCoFf
Ich habe gerade auch festgestellt, dass dieses Demo eine großartige Möglichkeit sein kann, mit Mustern aus CSS nth-Type-Selektoren zu spielen.
Das ist wirklich nett. Ich frage mich, ob ein Bild darin skriptet werden kann.
Sicher, das könnte es, wenn Sie das Muster der nth Quadrate herausfinden.
Zunächst einmal vielen Dank für diese wirklich großartige Innovation! Ich habe einige Fragen: Warum erlaubt request Animation Frame nicht, die Bildrate zu ändern? Warum sind 60fps der Standard und warum kann das nicht geändert werden? Oder kann es das?
Das können Sie, indem Sie es in ein setTimeout packen! Weitere Informationen finden Sie in diesem Artikel: http://creativejs.com/resources/requestanimationframe/
Ich habe einen Tutorial-Artikel auf Paul Irishs Blog gelesen, und er schlägt vor, den Aufruf der eigenen Funktion an den Anfang der Funktion zu verlagern, um näher an 60fps zu gelangen, wenn man die setTimeout-Fallback-Methode verwendet.
http://www.paulirish.com/2011/requestanimationframe-for-smart-animating/
Ich habe Probleme, eine Animationsfunktion zu verwenden, die eine Klassenmethode ist. Sie muss auf andere Eigenschaften und Methoden der Klasse zugreifen können, aber der Kontext, den ich erhalte, ist das Window-Objekt.
Ich habe versucht,
callundbindzu verwenden, aber es hat nicht funktioniert. Irgendwelche Ideen?Ich vermute, das ist nicht mehr relevant, aber eine der beiden sollte funktionieren
var animId = requestAnimationFrame(o.anim.bind(o)); // eingebundene bindoder
var animId = requestAnimationFrame(function(){o.anim()}); // manuelle bindDas Start-Stopp-Demo funktioniert in Safari (v5.1.7) furchtbar, in FF (v26) und Opera (v17.0) bei meinen Tests schlecht.
Es funktioniert nur gut in Chrome (30) und IE (v10).
Daher halte ich es für Zeitverschwendung, es zu implementieren. Bleiben Sie einfach bei der setInterval-Funktion mit Schritten von 16,67 ms (60 Hz).
Leider sind die Idioten hinter der Browserentwicklung und Standardisierung immer noch in der Technologie der 70er Jahre oder früher gefangen, als Genlock eingeführt wurde, um Videokameras mit VCRs zu synchronisieren, und ihre unglaubliche Dummheit und Nachlässigkeit beeinträchtigt uns immer noch alle.
Hallo Chris, tolle Lektion über requestanimationframe, ich muss wissen: Wie steuert man die Geschwindigkeit mit dieser Funktion?
Ich gehe davon aus, dass die beste Option darin besteht, Ihre Geschwindigkeit auf dem Zeitstempelparameter zu basieren, den es in den Callback übergibt
Alternativ könnten Sie ein externes setInterval verwenden, um Dinge zu bewegen und sie dann in requestAnimationFrame zu zeichnen.
Ich glaube nicht, dass Sie ändern können, wie oft requestAnimationFrame feuert, obwohl die Verwendung eines Monitors mit einer anderen Bildrate funktionieren könnte, aber ich denke, 60Hz ist universell.
Sie sagten „ruft sich selbst rekursiv auf“… Aber seien Sie vorsichtig, denn das ist keine Rekursion, wie Leute sie normalerweise verstehen (mit den Nebeneffekten von Stack-Speicher usw.).