User123: JavaScript Slideshow

Hallo, ich bin Neuling im Bereich Webentwicklung, bzw. Webdesign. Ich versuche gerade eine Slideshow zu erstellen. Hier ist mein JavaScript Code:


$(document).ready(function () {
   $("#foto").hide();
   $("#foto2").show();  
 });

setInterval(() => {
   $(document).ready(function () {
      setTimeout(function(){  
        setTimeout(function(){ 
         $("#foto2").fadeOut(1000); 
          setTimeout(function(){  
              $("#foto").fadeIn(1000); 
          },1000)
        },5000)
     
        setTimeout(function(){
           setTimeout(function(){
             $("#foto").fadeOut(1000); 
           },3000)
          setTimeout(function(){
            $("#foto2").fadeIn(1000);
          },4000)
        }, 10000)
     
     },0000)
    });
  
  
}, 17000);

Ich habe von Jquery gebrauch gemacht. Jetzt habe ich Folgendes problem: Beim ersten Durchlauf der Slideshow ist das Foto zu lange eingeblendet. Javascript rechnet offenbar das "set Timeout" und "set interval" zusammen. Kennt jemand eine Lösung?

  1. Hallo User123,

    das ist aber extremes setTimeout Gewusel, das Du da veranstaltest. Sehe ich das richtig, dass Du nur 2 Fotos abwechelnd anzeigst? Was soll das erst bei 30 Fotos werden?!

    Ich glaube auch, dass es wenig sinnvoll ist, einen ready-Handler in einem setInterval-Callback zu verwenden.

    Man erkennt, dass Du gerade erst einsteigst. Beschäftige Dich mit den Konzepten „Variablen“ und „Bedingte Anweisungen“. Ohne die lassen sich kaum sinnvolle Programme erstellen.

    Übrigens ist es in jQuery seit Version 3.0 Standard, einen Ready-Handler per $(...) zu registrieren und nicht per $(document).ready(...). Da es diese Möglichkeit schon seit jQuery 1.0 gibt, kann man diese Vorgehensweise generell empfehlen.

    Wie auch immer - du hast richtig erkannt, dass setInterval den ersten Aufruf des Intervall-Callbacks nicht sofort durchführt, sondern erst nach Ablauf der ersten Intervallfrist. Man könnte das so lösen, dass man die Callback-Funktion für setInterval nicht direkt übergibt, sondern als eigenständige Funktion schreibt. Und dann ruft man einmal diese Funktion auf und direkt dahinter setInterval. In etwa so:

    $(function() {
       zeigeBilddurchlauf();
       setInterval(zeigeBilddurchlauf, 10000);
    });
    
    function zeigeBilddurchlauf() {
       // setTimeout Gestrüpp
    }
    

    Aber das ist nicht schön, wirklich nicht. Bei 2 Bildern geht es noch, bei 20 oder 30 Bildern wird es tödlich. Deine fadeIn/fadeOut Steuerung kann man mit jQuery machen, sicher, aber es gibt in allen relevanten Browsern (Internet Explorer ab Version 10) die CSS Eigenschaften transition und opacity, womit Du das Ein-/Ausblenden auch ohne jQuery durchführen kannst. Einfach beim alten Bild die opacity auf 0 (=transparent) setzen, beim neuen Bild auf 1 (=undurchsichtig) und mit transition:opacity 1s; dafür sorgen, dass der Übergang auf eine Sekunden gestreckt wird. Damit erreichst Du auch, dass das alte Bild wegblendet, während das neue Bild schon einblendet.

    Eine einfache (aber ggf. netzwerkintensive) Version einer Slideshow braucht

    • einen Container mit einem img-Element pro Bild
    • alternativ ein figure-Element pro Bild, wenn Du auch eine Überschrift (figcaption) oder Zusatztexte unterbringen willst
    • eine Variable, die die aktuelle Bildnummer festhält
    • einen setInterval-Handler, der das aktuelle Bild ausblendet, die Bildnummer erhöht (bzw. bei Überlauf auf 0 zurücksetzt) und das neue Bild einblendet.
    • der setInterval Handler kann für das neue Bild, das er einblenden möchte, noch die Eigenschaft complete des Bildes abfragen. Diese Eigenschaft steht auf true, wenn das Bild geladen ist. Ist sie false, wird das Bild übersprungen und das nächste probiert. Oder man bleibt auf dem aktuellen Bild. Das richtige Vorgehen hängt auch daran, ob die Reihenfolge der angezeigten Bilder von Bedeutung ist oder nicht.
    • die Variante 2 kann man verfeinern, indem man den setInterval-Handler schneller laufen lässt als nötig (z.B. alle 0.5s). Im setInterval-Handler läuft ein Countdown. Bei einer Bildwechselzeit von 5s und einer Intervallfrequenz von 0.5s würde er bei 10 beginnen. Wenn der Countdown abgelaufen ist, wird der complete-Status des nächsten Bildes geprüft. Ist es da, wird der Countdown zurückgesetzt und das Bild aktiviert. Ist es noch nicht da, bleibt man auf dem aktuellen Bild und der Countdown tickt weiter (ins negative - was nicht stört wenn man < 1 abfragt und nicht == 0.

    Die Registrierung des setInterval-Handlers kann man in einem ready-Handler machen. Es ist allerdings riskant, weil der ready-Handler anläuft, sobald das DOM fertig ist. "DOM fertig" ist was anderes als "alle Bilder geladen" und wenn Du 40 Bilder hast, dann lädt der Browser die nicht zwangsweise in der Reihenfolge, wie sie im HTML auftauchen. Da hilft dann die erwähnte Nutzung des complete-Status.

    Eine komplexere Lösung verwendet nur zwei img Elemente. Eins ist aktuell und wird angezeigt, das andere ist ausgeblendet und dient zum Laden des nächsten Bildes. Wenn der Zeitpunkt zum Bildwechsel kommt, wird umgeblendet und die beiden wechseln die Rollen. Das hat den Vorteil, dass zu Beginn erstmal nur zwei Bilder geladen werden müssen. In einem langsamen Netz ist das ein deutlicher Vorteil. Auch hier kann man complete nutzen, um nicht auf ein Bild umzuschalten, das noch nicht fertig geladen ist.

    Rolf

    --
    sumpsi - posui - obstruxi
  2. Lieber User123,

    wenn es um Image-Slider geht, stellt sich für mich immer die Frage, welches DOM wollen wir haben und was davon soll JavaScript generieren. Wie universell soll das JavaScript sein und woher soll es wissen, was es zu tun hat?

    Ich habe von Jquery gebrauch gemacht.

    Das ist nur ein Werkzeug. Damit kann man tolle Sachen machen. Lies "toll" sowohl im Sinne von "beeindruckend" als auch im Sinne von "Tollwut".

    Aktuell manipulierst Du Elemente mit passenden ID-Bezeichnern, indem Du jQuery-Methoden (.hide(), .show(), .fadeIn() und fadeOut()) darauf ansetzt. Das kann man schon so machen, aber dann ist es halt nicht gut. Es tut was es soll, aber eben nur das. Will man es später einmal für etwas anderes einsetzen, ist es kaum mehr verständlich und muss ohnehin umgebaut oder besser ganz von vorne gebaut werden.

    Jetzt habe ich Folgendes problem: Beim ersten Durchlauf der Slideshow ist das Foto zu lange eingeblendet.

    Das ist eine unmittelbare Folge davon, dass Du noch am Anfang des Erfahrungsgewinns stehst. Du überblickst noch nicht alles, was Du da zusammengeschraubt hast.

    Javascript rechnet offenbar das "set Timeout" und "set interval" zusammen. Kennt jemand eine Lösung?

    Die Zeitliche Abfolge von Arbeitsschritten solltest Du irgendwie schematisch erfassen, damit Du weißt, was Du wie in Code fassen willst. Das kann so aussehen:

    1. schalte Bild 1 auf undurchsichtig (opaque)
    2. warte eine Zeit von x
    3. schalte Bild 2 auf undurchsichtig und Bild 1 auf durchsichtig
    4. warte eine Zeit von x
    5. ...?

    Diese Punkte können nicht in einer Schleife stehen, weil es in JavaScript keine Möglichkeit gibt, die Abarbeitung innerhalb des Codes anzuhalten. Deswegen behilft man sich mit zyklischen Aufrufen, die timer-gesteuert sind (Dein setInterval ist so ein Kandidat). Die zyklisch aufgerufene Funktion ermittelt dann, welchen Schritt dieser Liste sie gerade ausführen soll. Die Schritte 2 und 4 sind dann die Momente, in denen die Funktion sich beendet, um auf einen erneuten per setInterval ausgelösten Aufruf zu warten.

    Der Unterschied zwischen setTimeout und setInterval ist der, dass ersteres nur einen einzigen Aufruf auslöst, zweiteres dagegen wie ein Uhrwerk ständig Aufrufe erzeugt, bis man entweder die Seite wechselt, oder per JavaScript das Intervall wieder abstellt. Für einen automatischen Bildwechsler bietet sich daher zweiteres eher an.

    Liebe Grüße

    Felix Riesterer

    1. Hallo Felix,

      setIntervall
      setInterval

      Die Steuerung über eine Statusmaschine (was Du mit Schritten meintest) ist aber auch nicht trivial. Vor allem, wenn die Zeiten zwischen den Schritten variabel lang sind.

      Ohne Verständnis von Variablen und bedingten Anweisungen kommt man da nicht zurecht, weshalb ich den OP auch erstmal darauf verwiesen habe.

      Copy+Paste Scripting ist nichts, was ich unterstützen will.

      Rolf

      --
      sumpsi - posui - obstruxi
      1. Lieber Rolf,

        setIntervall
        setInterval

        Deinem scharfen Auge entgeht aber auch nix! Habe es sofort korrigiert. Danke.

        Die Steuerung über eine Statusmaschine (was Du mit Schritten meintest) ist aber auch nicht trivial. Vor allem, wenn die Zeiten zwischen den Schritten variabel lang sind.

        Völlig richtig.

        Ohne Verständnis von Variablen und bedingten Anweisungen kommt man da nicht zurecht, weshalb ich den OP auch erstmal darauf verwiesen habe.

        Die Verwendung von jQuery verführt dazu, auf Variablen mehr und mehr zu verzichten.

        Copy+Paste Scripting ist nichts, was ich unterstützen will.

        Da stehen wir beide auf derselben Seite.

        Liebe Grüße

        Felix Riesterer