Bilder zyklisch einblenden

Problem

Auf Seiten mit einem großen »Titelbild« – oft bei E-Commerce-Sites – wetteifern viele Produkte und/oder Abteilungen um diesen Bereich. Als Kompromiss wird dabei meist eine ganze Serie von Bildern zyklisch ein- und ausgeblendet. Das ist keine schlechte Idee, allerdings ist die Umsetzung häufig frustrierend, da viel zu viele Sites nicht die Möglichkeit bieten, die »Bilderschau« zu stoppen, um die Informationen auf einem der Bilder genauer in Augenschein zu nehmen.

Man sollte sich Gedanken darüber machen, was eine fortlaufende Animation für Folgen hat. Die meisten Anwender haben gelernt, nervige Werbungen zu ignorieren, die viel Bewegung enthalten. Die Designer und Entwickler müssen auch Anwender berücksichtigen, die kein Interesse an der Animation haben, den Rest der Seite aber durchaus lesen wollen. Schlimmert noch ist eine Situation, in der ein Anwender eines der Bilder tatsächlich anschauen möchte, dieses sich aber nicht stoppen lässt. Daher finden Sie in diesem Rezept eine Play/Pause-Funktionalität, damit die Benutzer nicht in einer endlosen animierten Schleife gefangen sind.

Lösung

Mit den jQuery-Methoden .fadeIn() und .fadeOut() können wir eine hübsche, zyklisch rotierende Animation erstellen, die über ein Array iteriert und die Opazität jedes Bildes abhängig von einem Timer verändert. Greifen wir auf das Wissen zurück, das wir uns beim Implementieren der Registerkarten-Lösung angeeignet haben, dann können wir Links auf jedes Bild erzeugen, durch die nicht nur das Ziel-Bild in den Vordergrund geholt, sondern auch noch eine Boolesche Variable pause gesetzt wird, um die Animation anzuhalten oder weiterlaufen zu lassen. Dies führt zu einem wirklich praktischen Bild-Rotierer, anstatt nur einen visuellen Genuss zu haben.

Rotator – HTML-Code

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<meta http-equiv="imagetoolbar" content="false" />
<title>jQuery-Kochbuch - Kapitel 13 - Bilder zyklisch einblenden</title>
<link rel="stylesheet" type="text/css" href="_common/basic.css" />
<link rel="stylesheet" type="text/css" href="rotator.css" />
<script type="text/javascript">
/* <![CDATA[ */
document.write('<link rel="stylesheet" type="text/css" href="preload.css" />');
/* ]]> */
</script>
<script type="text/javascript" src="_common/jquery.js"></script>
<script type="text/javascript" src="rotator.js"></script>
</head>
<body>
<div id="container">
  <div id="rotator_wrapper">
    <ul id="rotator">
      <li id="photo_1">
        <img src="_common/photo_1.jpg" alt="Foto" />
      </li>
      <li id="photo_2">
        <img src="_common/photo_2.jpg" alt="Foto" />
      </li>
      <li id="photo_3">
        <img src="_common/photo_3.jpg" alt="Foto" />
      </li>
      <li id="photo_4">
        <img src="_common/photo_4.jpg" alt="Foto" />
      </li>
      <li id="photo_5">
        <img src="_common/photo_5.jpg" alt="Foto" />
      </li>
    </ul>
    <ul id="rotator_controls">
      <li>
        <a href="#photo_1" class="current">1</a>
      </li>
      <li>
        <a href="#photo_2">2</a>
      </li>
      <li>
        <a href="#photo_3">3</a>
      </li>
      <li>
        <a href="#photo_4">4</a>
      </li>
      <li>
        <a href="#photo_5">5</a>
      </li>
    </ul>
    <a href="#" id="rotator_play_pause">PAUSE</a>
  </div>
</div>
</body>
</html>

Rotator – jQuery-Code

// Initialisieren
function init_rotator() {

  // Ist das Element vorhanden?
  if (!$('#rotator').length) {

    // Wenn nicht, beenden
    return;
  }

  // Rotations-Geschwindigkeit
  var speed = 2000;

  // Pause-Status
  var pause = false;

  // Rotator-Funktion
  function rotate(element) {

    // Stoppen, wenn der Anwender das wünscht
    if (pause) {
      return;
    }

    // Nächstes oder erstes <li>
    var $next_li = $(element).next('li').length ? 
                   $(element).next('li') : 
                   $('#rotator li:first');

    // Nächster oder erster Steuer-Link
    var $next_a = $('#rotator_controls a.current').parent('li').next('li').length ? 
                  $('#rotator_controls a.current').parent('li').next('li').find('a') : 
                  $('#rotator_controls a:first');

    // Animieren
    $('#rotator_controls a.current').removeClass('current');
    $next_a.addClass('current');

    // Fortsetzen
    function doIt() {
      rotate($next_li);
    }

    // <li> ausblenden
    $(element).fadeOut(speed);

    // Nächstes <li> anzeigen
    $($next_li).fadeIn(speed, function() {

      // kurze Verzögerung
      setTimeout(doIt, speed);
    });
  }

  // Click-Listener für Steuerelemente
  $('#rotator_controls a').click(function() {

    // Button-Text ändern
    $('#rotator_play_pause').html('PLAY');

    // Ziel anzeigen, andere <li> verbergen
    $($(this).attr('href')).show().siblings('li').hide();

    // class="current" hinzufügen und bei allen anderen entfernen
    $(this).addClass('current').parent('li').siblings('li')
           .find('a').removeClass('current');;

    // Animation pausieren
    pause = true;

    // Nicht folgen
    this.blur();
    return false;
  });

  // Pause / Play für Animation
  $('#rotator_play_pause').click(function() {

    // Was steht auf dem Button?
    if ($(this).html() === 'PAUSE') {

      // Rotation anhalten
      pause = true;

      // Text ändern
      $(this).html('PLAY');

    } else {

      // class="pause" entfernen
      pause = false;

      // Rotation fortfahren
      rotate('#rotator li:visible:first');

      // Text ändern
      $(this).html('PAUSE');
    }

    // Nicht folgen
    this.blur();
    return false;
  });

  // Alles bis auf erstes <li> verbergen
  $('#rotator li:first').siblings('li').hide();

  // Auf Laden der Seite warten
  $(window).load(function() {

    // Rotation beginnen
    rotate($('#rotator li:visible:first'));
  });
}

// Los geht's
$(document).ready(function() {
  init_rotator();
});

Diskussion

Dieses Rezept definiert zunächst zwei wichtige Variablen: speed (ein numerischer Wert in Millisekunden) und pause (ein Boolescher Wert, der festlegt, ob die Rotation laufen soll oder nicht). Die Geschwindigkeit wird hier in speed auf zwei Sekunden gesetzt und pause auf false, wodurch der Rotator beim Laden der Seite automatisch losläuft.

Innerhalb der Funktion rotate() gibt es eine Variable $next_li, die auf das nächste <li> nach dem aktuell animierten Eintrag zeigt. Ist dieser der letzte im Array, wird auf das erste <li> im Array verwiesen. Genauso wird bei den Links innerhalb von <ul id="rotator_controls"> vorgegangen, um einen visuellen Hinweis darauf zu geben, welches Bild gerade aktiv ist. Nach einer kurzen Verzögerung von zwei Sekunden wird die gesamte Abfolge wieder gestartet.

Wenn die Demo damit enden würde, könnte es ziemlich nervig sein, sich die Bilder anzuschauen – man kann den Ablauf nämlich nicht stoppen. Zum Glück können wir die Link-Technik für Verweise innerhalb der Seite nutzen, die wir bei der Registerkarten-Lösung kennengelernt haben. Dabei weisen wir einfach jedem der Links in <ul id="rotator_controls"> Click-Listener zu und zeigen dann das Ziel-Bild an, während wir den Rest verbergen. Zudem fügen wir einen Play/Pause-Button hinzu, der den Rotator startet oder wieder stoppt.

Schließlich haben wir noch den Code, der alles startet. Bis auf das erste <li> in <ul id="rotator"> werden alle verborgen, und wenn das Fenster fertig geladen ist, wird die Animation gestartet. Beachten Sie, dass $(window).load() etwas anderes ist als $(document).ready(), da bei der erstgenannten Funktion gewartet wird, bis alle Elemente der Seite vollständig geladen sind – auch die Bilder, was für einen Bild-Betrachter ziemlich wichtig ist. Die zweite hingegen wartet nur, bis die HTML-Struktur vollständig vorhanden ist, was für neue Funktionalität wichtig ist, die schon ablaufen kann, während die Bilder noch geladen werden. Beide Funktionen sind wichtig und jede hat ihre Berechtigung.

JQuery Kochbuch
titlepage.xhtml
part0000.html
part0001.html
part0002_split_000.html
part0002_split_001.html
part0002_split_002.html
part0003_split_000.html
part0003_split_001.html
part0003_split_002.html
part0003_split_003.html
part0003_split_004.html
part0003_split_005.html
part0003_split_006.html
part0003_split_007.html
part0004_split_000.html
part0004_split_001.html
part0004_split_002.html
part0004_split_003.html
part0004_split_004.html
part0004_split_005.html
part0004_split_006.html
part0004_split_007.html
part0004_split_008.html
part0004_split_009.html
part0004_split_010.html
part0004_split_011.html
part0004_split_012.html
part0004_split_013.html
part0004_split_014.html
part0004_split_015.html
part0004_split_016.html
part0004_split_017.html
part0004_split_018.html
part0005_split_000.html
part0005_split_001.html
part0005_split_002.html
part0005_split_003.html
part0005_split_004.html
part0005_split_005.html
part0005_split_006.html
part0005_split_007.html
part0005_split_008.html
part0005_split_009.html
part0005_split_010.html
part0005_split_011.html
part0005_split_012.html
part0005_split_013.html
part0006_split_000.html
part0006_split_001.html
part0006_split_002.html
part0006_split_003.html
part0006_split_004.html
part0006_split_005.html
part0006_split_006.html
part0006_split_007.html
part0006_split_008.html
part0006_split_009.html
part0006_split_010.html
part0007_split_000.html
part0007_split_001.html
part0007_split_002.html
part0007_split_003.html
part0007_split_004.html
part0007_split_005.html
part0007_split_006.html
part0007_split_007.html
part0007_split_008.html
part0007_split_009.html
part0007_split_010.html
part0007_split_011.html
part0008_split_000.html
part0008_split_001.html
part0008_split_002.html
part0008_split_003.html
part0008_split_004.html
part0008_split_005.html
part0008_split_006.html
part0008_split_007.html
part0008_split_008.html
part0008_split_009.html
part0008_split_010.html
part0008_split_011.html
part0008_split_012.html
part0008_split_013.html
part0008_split_014.html
part0008_split_015.html
part0008_split_016.html
part0008_split_017.html
part0008_split_018.html
part0008_split_019.html
part0008_split_020.html
part0008_split_021.html
part0008_split_022.html
part0009_split_000.html
part0009_split_001.html
part0009_split_002.html
part0009_split_003.html
part0009_split_004.html
part0009_split_005.html
part0009_split_006.html
part0009_split_007.html
part0009_split_008.html
part0009_split_009.html
part0009_split_010.html
part0010_split_000.html
part0010_split_001.html
part0010_split_002.html
part0010_split_003.html
part0010_split_004.html
part0010_split_005.html
part0010_split_006.html
part0010_split_007.html
part0010_split_008.html
part0010_split_009.html
part0010_split_010.html
part0010_split_011.html
part0011_split_000.html
part0011_split_001.html
part0011_split_002.html
part0011_split_003.html
part0011_split_004.html
part0011_split_005.html
part0011_split_006.html
part0011_split_007.html
part0011_split_008.html
part0011_split_009.html
part0011_split_010.html
part0011_split_011.html
part0012_split_000.html
part0012_split_001.html
part0012_split_002.html
part0012_split_003.html
part0012_split_004.html
part0012_split_005.html
part0012_split_006.html
part0012_split_007.html
part0012_split_008.html
part0013_split_000.html
part0013_split_001.html
part0013_split_002.html
part0013_split_003.html
part0013_split_004.html
part0013_split_005.html
part0013_split_006.html
part0013_split_007.html
part0013_split_008.html
part0013_split_009.html
part0013_split_010.html
part0013_split_011.html
part0013_split_012.html
part0014_split_000.html
part0014_split_001.html
part0014_split_002.html
part0014_split_003.html
part0014_split_004.html
part0014_split_005.html
part0014_split_006.html
part0014_split_007.html
part0014_split_008.html
part0014_split_009.html
part0014_split_010.html
part0014_split_011.html
part0015_split_000.html
part0015_split_001.html
part0015_split_002.html
part0015_split_003.html
part0015_split_004.html
part0015_split_005.html
part0015_split_006.html
part0015_split_007.html
part0015_split_008.html
part0015_split_009.html
part0015_split_010.html
part0016_split_000.html
part0016_split_001.html
part0016_split_002.html
part0016_split_003.html
part0016_split_004.html
part0016_split_005.html
part0016_split_006.html
part0016_split_007.html
part0016_split_008.html
part0016_split_009.html
part0017_split_000.html
part0017_split_001.html
part0017_split_002.html
part0017_split_003.html
part0017_split_004.html
part0017_split_005.html
part0017_split_006.html
part0017_split_007.html
part0017_split_008.html
part0017_split_009.html
part0017_split_010.html
part0017_split_011.html
part0018_split_000.html
part0018_split_001.html
part0018_split_002.html
part0018_split_003.html
part0018_split_004.html
part0018_split_005.html
part0018_split_006.html
part0019_split_000.html
part0019_split_001.html
part0019_split_002.html
part0019_split_003.html
part0019_split_004.html
part0019_split_005.html
part0019_split_006.html
part0019_split_007.html
part0019_split_008.html
part0019_split_009.html
part0019_split_010.html
part0020_split_000.html
part0020_split_001.html
part0020_split_002.html
part0020_split_003.html
part0020_split_004.html
part0020_split_005.html
part0020_split_006.html
part0020_split_007.html
part0020_split_008.html
part0021_split_000.html
part0021_split_001.html
part0021_split_002.html
part0021_split_003.html
part0021_split_004.html
part0021_split_005.html
part0021_split_006.html
part0021_split_007.html
part0021_split_008.html
part0021_split_009.html
part0022.html
part0023.html
part0024.html
part0025.html