Kursmaterial: Seite 3, Bewegte Bilder

Du hast dein eigenes HTML und CSS geschrieben. Wir haben gesehen, dass man JavaScript benutzen kann um Inhalte auf der Seite zu bewegen. Jetzt lernen wir, wie Programme direkt mit dem HTML geladen werden können, um unsere Seite dynamisch und interaktiv zu machen.

Eine JavaScript-Datei einbinden

Ziel

Verstehen, wie eine JavaScript-Umgebung eingerichtet werden kann.

Anweisungen

Erstelle in deinem Editor eine Datei mit dem Namen „slideshow.js“ in deinem slideshow-Verzeichnis.

Füge dann in slideshow.js die Zeile hinzu, die die Referenz auf den Film erzeugt:

var filmroll = document.getElementById('the-film-roll');

Binde die neue Datei am Ende von index.html ein:

<script src="slideshow.js"></script>

Wechsele in den Browser und lade die Seite neu. Gib folgendes in die Konsole ein:

filmroll.style.left = '-100px';

Erklärung

Halleluja! Ganz wie Bilder und Stylesheets, kann auch JavaScript-Code mit einer gesamten Seite geladen werden. Statt von Hand in die Konsole zu tippen, können wir ein Programm vorbereiten und es zusammen mit HTML, CSS und Bildern schicken.

Erstelle eine Funktion um den Film zu bewegen

Ziel

Die setInterval-Funktion für eine einfache Funktion verwenden.

Anweisungen

Gestern haben wir gesehen, dass setInterval benutzt werden kann um eine Funktion alle x Millisekunden auszuführen. Wir können das Ausführen der Funktion auch stoppen, indem wir clearInterval verwenden. Erweitere slideshow.js um den folgenden Code und lade dann die Seite neu:

var filmroll = document.getElementById('the-film-roll');
var start = 0;
var end = 200;
var current = start;

function move() {
  filmroll.style.left = current + 'px';
  current = current + 1;
  if (current > end) {
    clearInterval(loop); // This stops the loop
  }
}

var loop = setInterval(move, 40);

Warum eignen sich for- und while-Schleifen nicht für diesen Effekt?

Versuch, die Geschwindigkeit der Bewegung zu erhöhen. Es gibt zwei Wege. Welcher funktioniert besser?

Ändere die Funktion move so, dass sie den Film alle 50 Millisekunden um 20 Pixel bewegt.

Wie gehst du vor, um eine Bewegung von genau 110 Pixeln zu erzielen? Ändere deine Funktion so, dass sie genau zum Ende (und nicht weiter) läuft.

Tipp: Math.min ist eine Funktion, die beliebig viele Zahl-Werte als Parameter annimmt und den kleinsten Wert zurück gibt. Probier mal das:

current = Math.min(current + 20, end);

Lass sich die Fotos nach links bewegen statt nach rechts.

Um wieviel musst du den Film bewegen um vom ersten Foto zum zweiten zu gehen?

Was passiert wenn die Breite deines Fotos kein Vielfaches von 20 ist? Wie kannst du das Problem umgehen?

Ändere die Funktion move, so dass die Bewegungsrichtung nur von den Start- und Endwerten abhängt.

Erklärung

Um zu beeinflussen, wie schnell oder langsam eine Schleife ausgeführt wird, können wir die Zeit zwischen den Aufrufen der Funktion ändern oder ändern, wie groß der Effekt ist den jeder einzelne Aufruf hat.

Wir haben nun immer setInterval statt einer while- oder for-Schleife benutzt, um die Zeit zwischen den Aufrufen beeinflussen zu können, statt Tausender kleinster Veränderungen in Tausenden von Aufrufen zu machen.

Am Ende könnte deine Funktion beispielsweise so aussehen:

function move() {
  filmroll.style.left = current + 'px';

  if (current == end) {
    clearInterval(loop);
  }

  if (end > start) {
    current = Math.min(current + 20, end);
  } else {
    current = Math.max(current - 20, end);
  }
}

Mit den Funktionen Math.min und Max.max können wir sicher stellen, dass der Wert von current nie den Wert von end überschreitet. Dabei können wir den Wert von current entweder kleiner oder größer halten – je nach Bewegungsrichtung.

Eine Animations-Funktion bauen

Ziel

Schreibe eine wiederverwendbare Animations-Funktion die mehrfach ausgeführt werden kann.

Anweisungen

Schreibe eine Funktion namens scroll die eine Startposition und eine Endposition als Parameter nimmt.

function scroll(start, end) {
  // und nun?
}

Platziere die Zählvariable current, deine move-Funktion und setInterval in deine neue Funktion scroll. Variablen für Start und Ende musst du nicht mehr definieren. Deine Datei slideshow.js wird etwa so aussehen:

var filmroll = document.getElementById('the-film-roll');

function scroll(start, end) {
  var current = start;

  function move() {
    filmroll.style.left = current + 'px';

    if (current == end) {
      clearInterval(loop);
    }

    if (end > start) {
      current = Math.min(current + 20, end);
    } else {
      current = Math.max(current - 20, end);
    }
  }

  var loop = setInterval(move, 50);
}

Lade die Seite im Browser neu.

Benutze nun deine scroll-Funktion um zum zweiten Foto zu wechseln. Tippe dazu in die Konsole:

scroll(0, -500);

(… wobei statt 500 die Breite deines Fotos angegeben wird.)

Benutze die scroll-Funktion um vom zweiten zum dritten Foto zu wechseln.

Wechsele zurück zum zweiten Foto.

Erklärung

Nun haben wir eine einzige Funktion, mit der wir von links nach rechts und von jeder Start- zu jeder Endposition wechseln können!

Auf das keydown-Event reagieren

Ziel

Herausfinden, wie wir den Nutzer die Slideshow bedienen lassen können.

Anweisungen

Füge in slideshow.js einen Event Listener namens handleEvent für das document-Objekt hinzu. Der Event Listener ist eine Funktion, die im Falle eines keydown-Events ausgeführt werden soll. Die Funktion „hört“ also sozusagen auf das Ereignis „Taste runter“:

function handleEvent(e) {
  console.log(e, e.keyCode);
}

document.addEventListener('keydown', handleEvent);

Stelle sicher, dass die Developer Tools in Chrome geöffnet sind.

Lade die Seite neu.

Drücke Tasten auf deiner Tastatur und beobachte, was dabei in der Konsole ausgegeben wird.

Was sind die keyCodes für die linke und rechte Pfeiltaste?

Erweitere die handleEvent-Funktion, so dass sie eine Funktion aufruft, die den Film nach links bzw. rechts bewegt, wenn die linke oder rechte Pfeiltaste gedrückt wird:

function handleEvent(e) {
  backAndForth(e.keyCode);
}

function backAndForth(keyCode) {
  if (keyCode == 37) {
    scroll(500, 0);
  }

  if (keyCode == 39) {
    scroll(0, 500);
  }
}

(… wobei statt 500 die Breite deines Fotos angegeben

Teste die neue Funktion im Browser. Denke daran, die Seite immer neu zu laden, wenn du deinen JavaScript-Code im Editor geändert hast.

Warum bewegt es sich nicht weiter in die selbe Richtung, wenn du die selbe Pfeiltaste drückst?

Speichere die aktuelle Position in einer Variable und aktualisiere den Wert dieser Variable nach dem Aufrufen der scroll-Funktion. Benutze die aktuelle Position immer als den Wert für start when du die scroll-Funktion aufrufst.

Probier es erstmal alleine! Wenn du aber Hilfe brauchst, darfst du hier spicken:

var current = 0;

function backAndForth(keyCode) {
  if (keyCode == 37) {
    scroll(current, current - 500);
    current = current - 500;
  }

  if (keyCode == 39) {
    scroll(current, current + 500);
    current = current + 500;
  }
}

Erklärung

Wenn JavaScript in deinem Browser ausgeführt wird (also immer, außer es ist abgeschalten), „lauscht“ es durchgehend auf Events, wie zum Beispiel wenn du tippst oder deine Maus bewegst. Die Events haben Namen wie „keydown“, „keyup“, and „click“, und werden erzeugt, wenn irgendeines der entsprechenden Ereignisse eintritt. Sie werden dabei immer für das Element der Seite erzeugt, an dem sie auftreten, gelten aber auch für das Dokument insgesamt. Hier interessieren wir uns für die keydown-Events, die vom document ausgehen.

Indem wir auf die Events lauschen, können wir reagieren, wenn die Person vor dem Bildschirm mit der Seite interagiert. Wir können sehen, was getan wurde (was getippt wurde, was geklickt wurde) und dann etwas entsprechendes tun. In diesem Beispiel bewegen wir den Film nach links wenn die Person „links“ drückt, und nach rechts wenn sie „rechts“ drückt.

Durch lauschen auf Eingaben des Besuchers können wir ihm erlauben, die Seite zu steuern.

Damit kann man eine Menge machen!

Bugs finden und korrigieren

Ziel

Lernen, Events zu ignorieren, wenn eine Reaktion unerwünscht wäre.

Anweisungen

Unsere Funktionen um auf Events zu lauschen und zu animieren haben einen Fehler, einen Bug. Vielleicht hast du ihn schon bemerkt. Um den Bug hervorzurufen, drücke die linke und rechte Pfeiltaste abwechselnd und schneller als der Film sich bewegen kann. (Drücke also während die Bewegung noch stattfindet wieder „links“ oder „rechts“.) Du wirst ein unschönes Aufblitzen sehen.

Weißt du, was den Fehler verursacht? Wie kannst du ihn verhinden?

Versuche diesen Bug zu fixen.

Erklärung

Wenn wir programmieren, vergessen wir leicht, dass Besucher unserer Seite Dinge tun könnten, die keinen „Sinn“ machen oder die wir nicht vorher gesehen haben. Ohweh. Wir denken zwar, wir hätten unsere Arbeit getan, aber wenn wir herausfinden, dass unser Code einen Bug hat, müssen wir ihn beheben (oder den Nutzern sagen „Lass das!“, was sehr unhöflich ist.)

Erstmal müssen wir bemerken, dass der Bug existiert. Dann müssen wir herausfinden, warum er existiert. Dann müssen wir herausfinden, wie wir ihn beseitigen können. Viele Programmierer haben Spaß am Aufspüren von Bugs, weil sie ein spannendes Puzzle sind.

Hast du eine Lösung gefunden? Hier ist ein Vorschlag dafür:

var scrolling = false;

function scroll(start, end) {
  var current = start;

  var move = function () {
    filmroll.style.left = current + 'px';

    if (current == end) {
      clearInterval(loop);
      scrolling = false;
    }

    if (end > start) {
      current = Math.min(current + 20, end);
    } else {
      current = Math.max(current - 20, end);
    }
  }

  var loop = setInterval(move, 50);
  scrolling = true;
}

function handleEvent(e) {
  if (!scrolling) {
    backAndForth(e.keyCode);
  }
}

Wir haben eine Variable erzeugt in der wir uns merken ob sich der Film gerade bewegt. Falls er das tut, können wir das keydown-Event ignorieren wenn es eintritt.

Diese Lösung verwendet ein Ausrufungszeichen in der if (!scrolling)-Bedingung (in der Funktion handleEvent). Das Ausrufungszeichen nennt man den logischen NOT-Operator in JavaScript (also „nicht“, eine Verneinung). Die Bedingung if (!scrolling) bedeutet also: falls die Variable scrolling nicht true (wahr) ist.

Vielleicht passt diese Lösung aber gar nicht zu dem, was der Nutzer erwartet. Was würde der Nutzer hier wohl vernünftiger Weise erwarten? Wie können wir den Code so ändern, dass er sich so verhält, wie man erwarten würde?

Weiter!

Jetzt wo wir Änderungen am CSS gemacht haben, wollen wir auch das HTML verändern!

→ Zur vierten Seite.