Linuchs: Bildverzeichnis (Thumbnail) mit Javascript erzeugen

Moin,

ich habe HTML-Seiten (nicht PHP) mit Bildern <img src=...> und möchte ein Bildverzeichnis dieser Seite erstellen, also die Bilder im Kleinformat zeigen. Das ist zunächst leer:

<div id="thumbnails">
</div>

für jedes Bild soll so ein Eintrag eingefügt werden:

<div>
  <img src="[Dateiname]">
</div>

In Javascript mache ich dieses:

// Bildverzeichnis erstellen
var bilder = document.querySelectorAll( "img" );
console.log( bilder.length +" Bilder" );
thumbverzeichnis  = "";
for ( let i=0; i<bilder.length; i++ ) {
  console.log( bilder[i] );
  thumbverzeichnis  += "<div class='li bo'>\n";
  thumbverzeichnis  += bilder[i] +"\n";
  thumbverzeichnis  += "</div>\n";
}
document.querySelector( "#thumbnails"  ).innerHTML  = thumbverzeichnis;

Die Anzahl der Bilder wird korrekt gezeigt, mit console.log auch korrekt alle img-tags <img ...>

Aber nach Einfügen in #thumbnails wird nicht das Bild gezeigt, sondern sowas

Wie kann ich den String bekommen, den console.log anzeigt?

Gruß, Linuchs

  1. Hallo Linuchs,

    Moin,

    ich habe HTML-Seiten (nicht PHP) mit Bildern <img src=...> und möchte ein Bildverzeichnis dieser Seite erstellen, also die Bilder im Kleinformat zeigen.

    Bei reinen HTML-Seiten würde ich nicht bei jedem Neuladen mit JavaScript Bitmap-Miniaturansichten generieren. Ich würde dabei zwei Fälle unterscheiden:

    1. Du willst lediglich eine kleine Bildübersicht

    Dann verwende einfach die vorhandenen Bilder und skaliere diese mit CSS:

    <div class="bildverzeichnis">
      <a href="#bild1"><img src="bilder/haus.jpg" alt="Haus"></a>
      <a href="#bild2"><img src="bilder/garten.jpg" alt="Garten"></a>
      <a href="#bild3"><img src="bilder/zaun.jpg" alt="Zaun"></a>
    </div>
    
    .bildverzeichnis {
      display: grid;
      grid-template-columns: repeat(auto-fill, minmax(10rem, 1fr));
      gap: 1rem;
    }
    
    .bildverzeichnis img {
      display: block;
      width: 100%;
      height: 8rem;
      object-fit: contain;
    }
    

    2. Du willst thumbnails

    Dann würde ich das 1x

    a. manuell beim Upload

    b. mit PHP machen.

    Bis bald!
    Jonathan

    --
    Was ja kaum einer weiß:
    Lorem Ipsum ist ein Zitat von Julius Caesar, was übersetzt so viel heißt wie
    „Das schlimme am Internet ist, dass man nie weiß, ob Zitate echt sind.“
    1. Hallo Jonathan,

      danke für die Antwort. So wie du es vorschlägst, habe ich es bisher.

      Aber wenn ich dann ein Bild irgendwo in den Text einfüge, muss ich diesen Eintrag bei den Thumbnails nochmals machen. Das soll Javascript erledigen, kann doch eigentlich nicht schwer sein.

      Gruß, Linuchs

  2. Hallo Linuchs,

    in bilder[i] ist kein html, sondern das Image-Objekt. Und bei der Verkettung mit einem String wird daraus eben [object HTMLImageElement].

    Du müsstest die outerHTML Eigenschaft kopieren. Dann kommt auch das obligatorische alt-Attribut mit.

    Aber ideal ist das alles nicht. Ich habe nur keine Zeit für Details.

    Rolf

    --
    sumpsi - posui - obstruxi
    1. @@Rolf B

      Du müsstest die outerHTML Eigenschaft kopieren.

      Ja, damit ist das schnell gemacht: Warschau 1

      Dann kommt auch das obligatorische alt-Attribut mit.

      Hm, und wenn da kein Alternativtext ist? Dann könnte man sich den aus der Bildunterschrift rausholen. Dann muss man sich das img-Element zusammenbasteln: Warschau 2

      Es sei denn, es ist eine Verknüpfung vom Bild zur Bildunterschrift mit aria-describedby (oder aria-labelledby) vorhanden; die geht dann bei outerHTML auch mit zum Thumbnail: Warschau 3

      🖖 Live long and prosper

      --
      “Space: the final frontier. Above us. Around us. Within us.
      We have always looked to the stars to discover who we are.”

      — Michael Burnham in Star Trek: Discovery S2:E1
  3. @@Linuchs

    var bilder = document.querySelectorAll( "img" );
    

    Nö, das ist Quatsch. document.images existiert bereits.


    for ( let i=0; i<bilder.length; i++ ) {
    

    Die Tage der guten alten FOR-Schleife sind aber nun auch schon eine ganze Weile gezählt. Es gibt sicher noch Anwendungsfälle dafür, aber alle Elemente einer Sammlung zu durchlaufen, zählt nicht dazu; dafür gibt es forof.

    Dann musst du nicht mit Indizes rummachen und der Code wird lesbarer:

    for (const image of document.images) {
    	console.log(image);
    }
    

    Für etliche Objekttypen gibt es auch die forEach-Methode; nicht aber für HTMLCollection, was document.images ist. Kann man aber fix in ein Array umwandeln:

    [...document.images].forEach(image => {
    	console.log(image);
    });
    

      thumbverzeichnis  += "<div class='li bo'>\n";
    

    Das ist unlesbarer Code. Wofür steht 'li'? Wofür steht 'bo'?

    Und wozu sollen die div-Container überhaupt gut sein? Nur die img-Elemente sollten doch reichen?

    Und die Zeilenumbrüche interessieren den HTML-Parser nicht die Bohne, die \n können weg.

    🖖 Live long and prosper

    --
    “Space: the final frontier. Above us. Around us. Within us.
    We have always looked to the stars to discover who we are.”

    — Michael Burnham in Star Trek: Discovery S2:E1
    1. Hallo Gunnar Bittersmann,

      Kann man aber fix in ein Array umwandeln

      Bevor ich DAS täte, täte ich aber lieber querySelectorAll verwenden. Und zwar nicht auf das Dokument, sondern mit einem Selektor, der nur die Ausgangsliste trifft.

      Grund 1: es könnte noch anderswo auf der Seite Bilder geben

      Grund 2: images ist eine Live-Collection. Mit [... images] wird eine statische Kopie daraus, und das ist viel wichtiger, als for...of einsetzen zu können. Falls du die Thumbs hinter den Originalbildern erzeugst, dürfte ohne Kopie eine Endlosschleife drohen. Und wenn Du sie vorher einfügst, stimmen ohne Kopie die Indexe nicht mehr.

      Die Kopie ist aber unnötiger Aufwand, denn querySelectorAll ist zielgenauer und liefert von vornherein eine statische NodeList.

      Rolf

      --
      sumpsi - posui - obstruxi
    2. Hallo Gunnar,

      Das ist unlesbarer Code. Wofür steht 'li'? Wofür steht 'bo'?

      .li {float:left}
      .bo {border...}
      

      Es ist also eine bestimmte Art von Bildern, die im Text zu sehen sind.

      Ich weiß, für die Frage ist das überflüssig. Aber wenn ich den Code für die Frage verändere, schleichen sich mit Sicherheit Fehler ein.

      Gruß, Linuchs

  4. Danke für eure Nachfragen und Anregungen.

    Der Klartext bei console.log auf Objekte hat mich gedanklich in eine Sackgasse geführt, der ist programmtechnisch nicht (so einfach) zu haben.

    Ich brauche vom img-Objekt den src Wert und - danke für die Anregung - den alt Wert, und schon funktioniert es prächtig:

    // Bildverzeichnis erstellen
    var bilder            = document.querySelectorAll( ".bo img" );
    var thumbverzeichnis  = "";
    for ( let i=0; i<bilder.length; i++ ) {
      let src = bilder[i].src;
      let alt = bilder[i].alt
      console.log( src +"|" +alt );
      thumbverzeichnis  += "<div class='li bo'>";
      thumbverzeichnis  += "<img src='" +src +"' alt='" +alt +"'>";
      thumbverzeichnis  += (i+1) +". " +alt;
      thumbverzeichnis  += "</div>";
    }
    document.querySelector( "#thumbnails"  ).innerHTML  = thumbverzeichnis;
    

    Gruß, Linuchs

    1. Hallo Linuchs,

      naja, für einen gewissen Wert von "funktioniert".

      Deine bo li Namenswahl hat Gunnar schon angemerkt. Dass Du mit float hantierst statt eine Flexbox mit flex-flow:row wrap zu verwenden, finde ich auch nicht gerade modern. Die Thumbs sollten eine Liste sein, keine div-Wüste. Und wenn Du Thumb-Unterschriften setzen möchtest, dann mach daraus eine figure mit figcaption.

      Aber wenn Du zufrieden bist und es nur für Dich ist, will ich nichts weiter sagen…

      Rolf

      --
      sumpsi - posui - obstruxi
      1. @@Rolf B

        naja, für einen gewissen Wert von "funktioniert".

        Der näher an 0 als an 1 liegt?

        Und wenn Du Thumb-Unterschriften setzen möchtest, dann mach daraus eine figure mit figcaption.

        Hm … “The figure element represents some flow content, optionally with a caption, that is self-contained (like a complete sentence) and is typically referenced as a single unit from the main flow of the document”, sagt die Spec.

        Letzteres “is typically referenced as a single unit from the main flow of the document” sehe ich hier nicht gegeben. Nicht alles, was Bild mit Bildunterschrift ist, ist figure.

        🖖 Live long and prosper

        --
        “Space: the final frontier. Above us. Around us. Within us.
        We have always looked to the stars to discover who we are.”

        — Michael Burnham in Star Trek: Discovery S2:E1
    2. @@Linuchs

      Ich brauche vom img-Objekt den src Wert und - danke für die Anregung - den alt Wert, und schon funktioniert es prächtig:

      Zu der Einschätzung kannst du nur gelangt sein, weil du nicht getestet hast. Aber man sieht den Fehler auch schon im Code.

      Übrigens wäre es schön, wenn du bei Codeblöcken immer die Sprache (hier: JavaScript) angibst, dann gibt’s auch Syntax-Highlighting. Ich hab das mal für dich gemacht.


      var bilder            = document.querySelectorAll( ".bo img" );
      var thumbverzeichnis  = "";
      

      var? Das sollte anno 2026 nicht mehr auftauchen.

      bilder verändert sich nicht mehr, thumbverzeichnis hingegen doch. Also:

      const bilder = document.querySelectorAll( ".bo img" );
      let thumbverzeichnis = "";
      

      for ( let i=0; i<bilder.length; i++ ) {
      

      Immer noch? Warum?


        thumbverzeichnis  += "<div class='li bo'>";
        thumbverzeichnis  += "<img src='" +src +"' alt='" +alt +"'>";
        thumbverzeichnis  += (i+1) +". " +alt;
        thumbverzeichnis  += "</div>";
      

      Das ist unlesbarer Code. So wird’s lesbar:

        thumbverzeichnis += `<div class='li bo'>
          <img src='${src}' alt='${alt}'>
          ${i+1}. ${alt}
        </div>`;
      

      Und jetzt ist auch der Fehler deutlich zu sehen: alt wird zweimal ausgegeben, von Screenreadern also zweimal vorgelesen. Das will man nicht, es ist hier alt='' zu setzen, so wie es auch in meinen bereits verlinkten Beispielen der Fall ist. Die hattest du dir angesehen?

        thumbverzeichnis += `<div class='li bo'>
          <img src='${src}' alt=''>
          ${i+1}. ${alt}
        </div>`;
      

      Du willst die Bilder durchnummerieren? Das deutet darauf hin, dass du ol/li verwenden willst anstatt div.

      🖖 Live long and prosper

      --
      “Space: the final frontier. Above us. Around us. Within us.
      We have always looked to the stars to discover who we are.”

      — Michael Burnham in Star Trek: Discovery S2:E1
      1. @@Gunnar Bittersmann

        for ( let i=0; i<bilder.length; i++ ) {
        

        Immer noch? Warum?

        Falls die Antwort darauf „Nummerierung“ sein sollte – die bekommt man auch anders hin.

        forEach kann man auch mit zusätzlichem Parameter aufrufen:
        .forEach((item, index) => {});, dann hat man innerhalb der Funktion Zugriff auf den aktuellen Index.

        Die Nummerierung kann man aber auch CSS überlassen: siehe counter().

        Und wenn man wie bereits vorgeschlagen Listen-Markup verwendet, kann man sich das Initialisieren und Hochsetzen eines eigenen Zählers sparen und den bei Listen schon vorhandenen Zähler list-item verwenden. Beispiel

        🖖 Live long and prosper

        --
        “Space: the final frontier. Above us. Around us. Within us.
        We have always looked to the stars to discover who we are.”

        — Michael Burnham in Star Trek: Discovery S2:E1