JavaScript-Animation, die funktioniert (Teil 3 von 4)

In unserem ersten Beitrag dieser Serie haben wir vorgestellt Sprit, und wie es verwendet werden kann, um einfache und effektive Cross-Browser-Animationen im Web zu erstellen. Im zweiten Post haben wir ein paar einfache Animationen in Betrieb genommen, obwohl sie ziemlich viele Fehler hatten und der Code sicherlich nicht bereit war, live zu gehen.

Heute werden wir diese Fehler beheben und unseren Code bereinigen, sodass wir ihn auf einer Seite veröffentlichen können, ohne befürchten zu müssen, dass Code mit einer aufgerufenen Methode abstürzt Verkapselung.

Variabler Umfang

Um wirklich zu erklären, was im letzten Schritt so falsch mit dem Code war und warum die Kapselung so wichtig ist, müssen wir zunächst den Gültigkeitsbereich der Variablen erklären.

Stellen Sie sich vor, Sie arbeiten mit dem folgenden Code. Sie haben eine hilfreiche Variable in Ihrer Funktion mach das(), und Sie möchten dieselbe Variable in einer anderen Funktion verwenden, TU das(), aber Sie stoßen auf ein kleines Problem.

 function do_this () var very_helpful_variable = 20;… // Dies zeigt '20' an, genau wie Sie eine Warnung erwarten (very_helpful_variable);  function do_that () alert (very_helpful_variable); // Aber das zeigt 'undefined'! 

Ihre Variable funktioniert hervorragend innerhalb der deklarierten Funktion, aber außerhalb dieser Funktion ist es, als ob sie niemals existiert hätte! Das ist weil TU das() ist nicht im Umfang der Variablen sehr hilfreiche_Variable.

Variablen sind nur innerhalb des Codeblocks verfügbar, in dem sie deklariert werden. Dies ist deren Gültigkeitsbereich. Sobald der Codeblock fertig ausgeführt ist, werden seine Variablen gelöscht.

Schauen Sie sich diese Beispiele an:

 var w = 1; Funktion a () var x = 2; Funktion b () var y = 3; Alarm (w); // funktioniert Alarm (x); // funktioniert Alarm (y); // funktioniert Alarm (z); // undefined alert (w); // funktioniert Alarm (x); // funktioniert Alarm (y); // undefinierte Warnung (z); // undefined Funktion c () var z = 4; Alarm (w); // funktioniert Alarm (x); // undefinierte Warnung (y); // undefinierte Warnung (z); // funktioniert b (); // undefined alert (w); // funktioniert Alarm (x); // undefinierte Warnung (y); // undefinierte Warnung (z); // nicht definiert

Zuerst haben wir die Variable w, die außerhalb von Funktionen deklariert ist. Es heißt a Globale Variable, und es funktioniert überall, da es sich um das gesamte Dokument handelt.

Als nächstes ist die Variable x, da es innerhalb der Funktion deklariert ist ein(), es funktioniert nur innerhalb dieser Funktion. Dazu gehört auch das Arbeiten innerhalb der Funktion b (), schon seit b () ist innerhalb von ein().

Eine innerhalb von definierte Variable b () (mögen y) funktioniert nicht in der äußeren Funktion, da dies außerhalb des Gültigkeitsbereichs liegt.

Möglicherweise stellen Sie auch fest, dass wir versuchten, die Funktion aufzurufen b () aus der Funktion heraus c (); Funktionsnamen folgen den gleichen Regeln wie andere Variablen.

Ein weiteres Problem mit JavaScript, wenn wir einfach einen Variablennamen in einer Funktion verwenden, ohne ihn mit dem Schlüsselwort zu deklarieren var, Dann nimmt der Browser an, dass diese Variable global sein sollte. Wenn Sie also nicht sicherstellen, dass Sie Ihre Variablen immer mit der var Stichwort, werden Sie mit globalen Variablen enden und es nicht realisieren!

Zusammenfassend gilt: Wenn wir eine Variable deklarieren, können wir sie innerhalb dieses Codeblocks oder innerhalb von verschachtelten Blöcken verwenden. Wenn wir versuchen, es außerhalb seines Gültigkeitsbereichs zu verwenden, wird der Wert auf festgelegt nicht definiert.

Deshalb setzen wir in unserem letzten Beitrag das Timer Variable außerhalb der Funktionen, die es verwendet haben, da wir diese Variable nach dem Beenden der Funktionen noch packen mussten.

 var Timer; // Dies ist eine globale Variable function run_right (stage, left) … timer = setTimeout (function () run_right (2, left);, 200);… function stop_running () document.getElementById ('j' ) .style.backgroundPosition = "0px 0px"; // Wenn 'Timer' nicht als global festgelegt wurde, konnten wir ihn hier nicht stoppen. ClearTimeout (timer); 

Um den Timer zu löschen, brauchten wir Hör auf zu rennen() innerhalb der Gültigkeitsbereiche der Variablen sein Timer. Also haben wir gemacht Timer eine globale Variable, die überall verwendet werden kann, was daran falsch sein könnte?

Das Problem mit globalen Variablen

In einem bestimmten Bereich ist es unmöglich, zwei Elemente zu haben, die dasselbe heißen. Wenn Sie versuchen, zwei verschiedene Variablen mit demselben Namen zu verwenden, schreibt der Browser nur eine davon. Also, wenn wir eine Variable hätten Timer, und hatte eine separate Variable, die auch benannt wurde Timer das wurde im selben Rahmen aufgerufen, einer löschte sich und ersetzte den anderen, und wir hätten Chaos in unserem Code. Wenn wir eine hatten Globale Variable namens Timer, dann würde es mit jeder anderen benannten Variable interferieren Timer irgendwo auf der Seite enthalten - einschließlich aller angehängten JavaScript-Bibliotheken und externen Dateien.

Dies ist eine riesige Quelle von Kopfschmerzen, Sie haben gerade ein wirklich ordentliches JavaScript-Plug-In gesehen, und Sie laden es auf Ihre Website herunter, und plötzlich stürzen alle Ihre anderen Plug-Ins ab Variablen, die zufällig denselben Namen mit etwas anderem teilen, wird Ihr Browser von selbst übergangen, und die gesamte Seite kommt zum Erliegen.

Umso schlimmer ist, dass Sie dieses Problem beim ersten Testen des Codes nie bemerken werden. Wie unser Animationscode aus dem letzten Beitrag wird er von selbst großartig funktionieren. Je mehr Teile Sie jedoch hinzufügen, desto wahrscheinlicher ist es, dass Sie einen Namenskonflikt haben, und Sie werden durch ein Dutzend verschiedener JavaScript-Dateien blättern und herausfinden, welche beiden nicht auskommen.

Nun fragen Sie sich vielleicht: "Globale Variablen sind so bequem. Was ist, wenn ich meinen Code nur genau hinschaue und sicherstellen, dass ich keine Konflikte habe?" Das könnte in einer perfekten Welt funktionieren, aber in der Realität werden Sie oft mehrere Personen an verschiedenen Stellen auf derselben Seite arbeiten, oder Sie müssen Jahre später zurückkommen und verschiedene Teile Ihres Codes aktualisieren oder sogar Code von Drittanbietern haben Ihre Seite, die außerhalb Ihrer Kontrolle liegt (wie bezahlte Werbung).

Kurz gesagt, Sie möchten keine globalen Variablen mehr als die freiliegende Verkabelung an den Wänden Ihres Hauses oder die exponierte Maschine in Ihrem Auto. Es ist nur eine Frage der Zeit, bis etwas passiert, das die Arbeiten auflöst. Glücklicherweise gibt es einen besseren Weg, um diese Fallstricke zu vermeiden.

Verkapselung

Wir können alle Vorteile von globalen Variablen ohne Probleme mit einer aufgerufenen Technik nutzen Verkapselung. Stellen Sie sich vor, Sie bauen eine Mauer um den Code mit nur wenigen speziellen Türen. Nichts kann in diesen Code hinein oder aus ihm heraus, wenn Sie es nicht ausdrücklich zulassen.

JavaScript hat einen Variablentyp namens an Objekt. Objekte sind benutzerdefinierte Datensammlungen, die Informationen und Funktionen enthalten (als bezeichnet Eigenschaften und Methoden, beziehungsweise). Wir werden eine Funktion schreiben, die ein spezielles Objekt erstellt, das alle Funktionen enthält, die wir "gebacken" haben, und es uns sogar erlauben wird, mehr als einen Roboter zu haben, ohne unseren Code duplizieren zu müssen!

Wir beginnen mit der Definition einer neuen Funktion mit einem Variablennamen. Wir müssen der Variablen einige Argumente übergeben, ich werde das HTML-Element übergeben, das wir animieren, sowie einige eindeutige Werte für die Laufgeschwindigkeit und die Sprunghöhe, damit wir diese von Roboter zu Roboter variieren können.

 var RobotMaker = function (robot, run_speed, jump_height) // Wir werden alle unsere Funktionen und Variablen in diesen Bereich einfügen. // Dies ist in unserer "undurchdringlichen" Wand, daher steht nichts in diesem // Bereich in Konflikt mit anderem Code. return // Hier drinnen platzieren wir alle unsere 'Türen' ... // // Nur so kann alles in diesen Code hinein oder aus ihm herauskommen. // Und da dies immer noch im selben Bereich // wie bei RobotMaker liegt, können wir alle oben genannten Variablen verwenden! 

Da wir all unsere Funktionen in unsere neue "Wand" einfügen werden, wäre jetzt ein guter Zeitpunkt, um die Fehler, die wir mit dem ursprünglichen Code hatten, noch einmal zu überdenken. (Sie können das hier in Aktion sehen)

Sie stellen möglicherweise fest, dass wir zwei Schaltflächen (oder eine Schaltfläche zum Ausführen und Springen) anklicken, ohne auf die Schaltfläche zu klicken Halt Wenn Sie die Taste dazwischen drücken, führt J weiterhin beide Aktionen aus. Ein zweites Problem ist, dass egal in welche Richtung J schaut, wenn wir auf klicken Springen oder Halt Knopf, er steht jedes Mal richtig. Schließlich, wenn Sie auf die Schaltfläche klicken Springen Wenn der Knopf erneut gedrückt wird, während J von einem ersten Sprung fällt, fällt er in einer Endlosschleife weiter durch die Seite.

Um diese Dinge anzugehen, müssen wir genauer festlegen, was mit jeder unserer Funktionen geschehen soll:

Wenn wir auf Rechts ausführen klicken:

  1. Wenn J springt, machen Sie nichts und setzen Sie den Sprung fort
  2. Wenn J nach links läuft, stoppen Sie ihn nach links
  3. Nach rechts laufen und zum richtigen Rahmen animieren
  4. Wenn J das Ende der Etappe erreicht, stoppen Sie den Lauf und stehen Sie nach rechts

Wenn wir auf Run Left klicken:

  1. Wenn J springt, machen Sie nichts und setzen Sie den Sprung fort
  2. Wenn J richtig läuft, stoppen Sie ihn
  3. Nach links laufen und zum richtigen Rahmen animieren
  4. Wenn J das Ende der Etappe erreicht, stoppen Sie den Lauf und stehen Sie nach links

Wenn wir auf Stop Running klicken:

  1. Wenn J springt, machen Sie nichts und setzen Sie den Sprung fort (wir wollen nicht mitten in der Luft aufhören!)
  2. Wenn Sie rechts oder links laufen, hören Sie auf zu laufen
  3. Wenn Sie nach rechts schauen, stehen Sie nach rechts. Wenn Sie nach links schauen, stehen Sie nach links

Wenn wir auf Jump klicken:

  1. Wenn J springt, machen Sie nichts und setzen Sie den Sprung fort (wir wollen nicht wieder mitten in der Luft springen!)
  2. Wenn J rechts oder links läuft, hören Sie auf zu laufen
  3. Starte den Sprung. Wenn J nach rechts zeigt, springen Sie nach rechts. Wenn Sie nach links schauen, springen Sie nach links
  4. Land in dieselbe Richtung wie der Sprung

Zunächst werden wir jetzt einige weitere Variablen hinzufügen. Da sich der Timer beim Laufen und Springen unterschiedlich verhalten sollte, haben wir zwei separate Timer. Wir möchten auch ein vorstellen boolean (wahr / falsch) Variable, um nachzuverfolgen, ob wir nach links oder rechts blicken sollten, und wir werden eine Bühne Variable, nur um zu vermeiden, dass Sie den vollständigen Elementnamen eingeben müssen.

 // Innerhalb der RobotMaker-Funktion… var stage = document.getElementById ('stage'); var run_timer, jump_timer; var face_right = true;

Dann werden wir unsere Funktionen für Rechtslauf, Linkslauf und Springen wieder hinzufügen. Diese werden größtenteils gleich sein, mit einigen Unterschieden. Zunächst können alle Verweise auf das Element, das wir animieren, durch die Variable ersetzt werden Roboter (das als eines der Argumente in der übergeben wird RobotMaker Funktion). Zweitens haben wir die Laufgeschwindigkeit und die Sprunghöhe in den Funktionen geringfügig geändert, so dass wir diese durch Übergabe verschiedener Werte variieren können. Drittens benutzen wir die face_right Variable, um zu verfolgen, in welche Richtung J gerichtet ist (und in der Sprungfunktion, mit face_right zu entscheiden, welches Sprite Sprite zeigen soll). Schließlich verwenden wir separate Timer zum Laufen und Springen.

 // Innerhalb der RobotMaker-Funktion… Funktion run_r (Phase, links) face_right = true; if ((links + (15 * Laufgeschwindigkeit)) < (stage.offsetWidth - robot.offsetWidth)) left = left + (15 * run_speed); robot.style.left = left+"px"; switch (phase) case 1: robot.style.backgroundPosition = "-40px 0px"; run_timer = setTimeout(function()run_r(2, left);, 200); break; case 2: robot.style.backgroundPosition = "-80px 0px"; run_timer = setTimeout(function()run_r(3, left);, 200); break; case 3: robot.style.backgroundPosition = "-120px 0px"; run_timer = setTimeout(function()run_r(4, left);, 200); break; case 4: robot.style.backgroundPosition = "-80px 0px"; run_timer = setTimeout(function()run_r(1, left);, 200); break;   else  robot.style.backgroundPosition = "0px 0px";   function run_l(phase, left) face_right = false; if (0 < robot.offsetLeft - (15 * run_speed)) left = left - (15 * run_speed); robot.style.left = left+"px"; switch (phase) case 1: robot.style.backgroundPosition = "-40px -50px"; run_timer = setTimeout(function()run_l(2, left);, 200); break; case 2: robot.style.backgroundPosition = "-80px -50px"; run_timer = setTimeout(function()run_l(3, left);, 200); break; case 3: robot.style.backgroundPosition = "-120px -50px"; run_timer = setTimeout(function()run_l(4, left);, 200); break; case 4: robot.style.backgroundPosition = "-80px -50px"; run_timer = setTimeout(function()run_l(1, left);, 200); break;   else  robot.style.backgroundPosition = "0px -50px";   function jmp(up, top) if (face_right) robot.style.backgroundPosition = "-160px 0px";  else  robot.style.backgroundPosition = "-160px -50px";  if (up && (robot.offsetTop > (20 * (1 / Sprunghöhe)))) top = top - (top * .1); robot.style.top = top + "px"; jump_timer = setTimeout (function () jmp (nach oben, oben);, 60);  else if (up) up = falsch; jump_timer = setTimeout (function () jmp (nach oben, oben);, 60);  else if (! up && (robot.offsetTop.) < 115)) top = top + (top * .1); robot.style.top = top+"px"; jump_timer = setTimeout(function()jmp(up, top);, 60);  else  robot.style.top = "120px"; if (face_right) robot.style.backgroundPosition = "0px 0px";  else  robot.style.backgroundPosition = "0px -50px";  jump_timer = false;  

Alle diese Variablen und Funktionen befinden sich innerhalb unserer "Wand", sodass wir jetzt "Türen" erstellen müssen, um nur auf das zugreifen zu können, was wir benötigen. Diese vier "Türen" sind Gegenstand Methoden für die gleichen vier Funktionen, die wir zuvor hatten und werden die geschützten Funktionen oben referenzieren. Außerdem werden wir die Fehlerbehebung abschließen, indem Sie in jeder Funktion überprüfen, ob jump_timer geht, und dann stellen Sie sicher, dass die löschen run_timer. Denken Sie daran, dass diese beiden Zeitgeber irgendwo in der Zeitzone liegen RobotMaker () Funktion, damit wir sie hier verwenden können. Da es sich jedoch nicht um globale Variablen handelt, werden wir an anderer Stelle keine Probleme damit haben.

 // Innerhalb der RobotMaker-Funktion… return run_right: function () if (! Jump_timer || jump_timer == undefined) clearTimeout (run_timer); run_r (1, robot.offsetLeft); , run_left: function () if (! jump_timer || jump_timer == undefined) clearTimeout (run_timer); run_l (1, robot.offsetLeft); , stop_running: function () if (! jump_timer || jump_timer == undefined) clearTimeout (run_timer); if (face_right) robot.style.backgroundPosition = "0px 0px";  else robot.style.backgroundPosition = "0px -50px"; , jump: function () if (! jump_timer || jump_timer == undefined) clearTimeout (run_timer); jmp (wahr, robot.offsetTop); 

Nachdem wir nun eine Funktion zum Erstellen von Objekten geschrieben haben, können wir sie so oft verwenden, wie wir Objekte mit den gewünschten Animationseigenschaften erstellen möchten. Am Ende unserer Seite werden wir zwei neue deklarieren RobotMaker Objekte, und übergeben Sie ihnen das Element, das Sie animieren möchten, eine Laufgeschwindigkeit und eine Sprunghöhe.

 var j = RobotMaker (document.getElementById ('j'), 1, 1); var j2 = RobotMaker (document.getElementById ('j2'), .8, 5);

Jetzt haben wir keine Gefahr mehr im RobotMaker () Funktion leckt und stört unseren Code, und wir können immer noch die gewünschten Funktionen durch die "Türen" erreichen, die wir wie folgt installiert haben:

 

So können Sie jetzt das fertige Produkt auf dem hyrgo Pen sehen.

Beachten Sie, dass es keine Probleme mehr mit den Funktionen gibt, die sich gegenseitig beeinflussen, und Sie können jeden Roboter einzeln bedienen, ohne den anderen zu beeinflussen. Encapsulation ist eine unglaublich wichtige Technik, und Sie sollten sich wirklich damit vertraut machen, wenn Sie interaktives Webdesign erstellen möchten.

Wenn Sie möchten, checken Sie bitte den gesamten Code aus, der vollständig kommentiert ist, und Sie können die Sprites über die folgenden Links abrufen: Hier sind die ersten und die zweiten Sprites. Damit derselbe Code mit beiden Sprites funktioniert, musste das zweite Sprite in genau demselben Format und denselben Abmessungen wie das erste erstellt werden.

Fazit

Damit ist der dritte Teil des Spritings abgeschlossen! In unserem nächsten und letzten Post werde ich diese Schaltflächen ersetzen, indem unsere Roboter der Maus auf dem Bildschirm folgen und Ihnen die Einrichtung zeigen Ereignis-Hörer Unterstützung für Browser und Touch-Geräte aktivieren.