Bilder während scrollen erscheinen lassen

Igäl

Erfahrenes Mitglied
Liebe alle

Wiedermal brauche ich einen Denkanstoss.

Setting: ich habe zwei Spalten (divs). Im rechten div ist viel Text. Bei Overflow (also eigentlich immer) ist das div scrollable. Nun möchte ich, dass im linken div ein Bild erscheint, wenn eine bestimmte Stelle im Text erreicht ("erscrollt") ist. Bei der nächsten "Bildstelle" soll das Bild dann wieder ausgeblendet und das neue Bild eingeblendet werden.

Hat jemand eine Idee, wie das konzeptuell aussehen könnte? Und ob das überhaupt möglich ist?

Danke für die Inputs und euch allen weiterhin eine gute Woche.

So long, dä Igäl
 
Lösung
Ich denke, auch hier kann ich einen Denkanstoß geben:
Hier kann dir sicher der Intersection-Observer weiter helfen. Dieser überwacht die Scrollposition und ruft eine Funktion auf, wenn ein bestimmtes Element in den Viewport gelangt. Damit kannst Du z. B. ein p-Element überwachen oder, wenn es nur eine kleine Stelle im Text sein soll, diese in ein span wrappen und dieses überwachen.
Das mit dem Bild würde ich so regeln, dass Du ein data-Attribut an der betr. Textstelle bzw. dem span anbringst, die die URL des Bildes enthält. Dann kannst Du jeweils das Bild, das dazu gehört einblenden.
Beim Debuggen gibt es im wesentlichen zwei Möglichkeiten:
  1. Mit console.log Ausgaben machen lassen. Leichter Einstieg aber etwas Zeit raubend.
  2. Den Debugger in den Entwicklerwerkzeugen deines Browsers benutzen. Führt schneller zum Ziel und wenn Du Debugger von anderen Programmiersprachen kennst, dürfte der Einstieg ebenfalls leicht sein.
 
Hab mir dafür jetzt ein Plugin geholt und arbeite mit console.log. Noch eine letzte Frage, um zu schauen, ob ich auf der richtigen Fährte bin.

wenn ich mit querySelectorAll arbeite, bekomme ich ja eine node-list. Da kann ich mittlerweile durchiterieren und bekomme den Wert aus meiner Eigenschaft "data-path" für jedes Bild an der jeweiligen Textstelle geliefert.

So wie ich mich jetzt durchgelesen habe, kann ich aber nun nicht mehr einfach eine Callbackfunktion schreiben sondern das sieht dann irgendwie aus wie folgt (gibt noch nen Syntaxerror und ich versteh noch nicht genau, was das mit dem ( n ) da soll, aber da komm ich schon noch dahinter :) ):
Javascript:
    const imgObserver = newIntersectionObserver(function(entries) {
            entries.forEach((n) => {
                console.log(n);
            )};
        }, objOptions);

Muss ich die Funktion da direkt in den Funktionsaufruf schreiben oder kann ich forEach auch in eine Funktion schreiben, die ausserhalb liegt? Phuu... ganz vergessen wie zeitraubend es ist, wenn man sich etwas neu beibringt :) Wenn ich die Basics beieinander habe, nerv ich dann auch nicht mehr :)
 
Muss ich die Funktion da direkt in den Funktionsaufruf schreiben oder kann ich forEach auch in eine Funktion schreiben, die ausserhalb liegt?
Natürlich, Du brauchst nur die Referenz der Funktion zu übergeben:
Code:
function callbackIntersect(entries) {
    entries.forEach((n) => {
        console.log(n);
    )};
}
const imgObserver = newIntersectionObserver(callbackIntersect, objOptions);
Nicht davon irritieren lassen, dass in der letzten Zeile nur der Name übergeben wird und vom Parameter keine Rede ist, Javascript übergibt immer die Entries.
 
Gut, dann bin ich schonmal einen grossen Schritt weiter. Vielen Dank. Anbei die Geschichte, soweit ich sie habe:

Javascript:
    var targets = [
        Array.from(document.querySelectorAll(".imgTrigger")),
    ].flat();
    const bookImg = document.querySelector(".bookImg");

    var switchImage = function(entries, observer) {
        entries.forEach((entry, i) => {
            console.log(i); //iteriert korrekt
            if(entry.isIntersecting) {
//HIER liegt das Problem
                console.log(targets[i]); //immer nur der Wert der Eigenschaft 'data-path' des ersten observed Dingens
                bookImg.setAttribute("src", targets[i].getAttribute("data-path"));
                bookImg.classList.remove("hidden");
            }else{
                bookImg.classList.add("hidden");
            }
        });
    };


    const objOptions = {
        root: null,
        threshold: 1,
        rootMargin: "0px",
    };
 
    //checkedicheck
    console.log(imgTrigger);

    for(let i = 0; i < imgTrigger.length; i++) {
        console.log(imgTrigger[i]);
        console.log(imgTrigger[i].getAttribute("data-path"));
    }
    //end checkedicheck

    const imgObserver = new IntersectionObserver(switchImage, objOptions);

    var targets = [
        Array.from(document.querySelectorAll(".imgTrigger")),
    ].flat();

    targets.forEach((target) => imgObserver.observe(target));
Drei <span>-Tags werden observed und die erscheinen auch immer dann, wenn sie sollen. Nur wechselt das Bild sich nicht aus. Ich erhalte bei allen drei Bildern dasjenige Bild angezeigt, welches als erstes geladen worden ist. Ich starte aber mit einer leeren Source-Eigenschaft, so das also tatsächlich etwas eingefüllt wird.
HTML:
<img id="bookSidePic" class="bookImg hidden" src="">

Wenn das Bild jeweils aus und wieder eingeblendet wird, verändert sich "src" jedoch nicht. Siehst du, wo mein Überlegungsfehler liegt? Ich bin noch dabei hinter die Logik der JS-Sache zu kommen. Es ist etwas verwirrend :)

Edit: gerade gesehen, dass ich Bullshit gemacht habe mit imgTrigger und zusätzlich noch das targets-array. Ich lass den Post mal und würde ihn wieder löschen, wenn ich bald dahinterkomme :)

Edit2: den Bullshit mal etwas entwirrt und oben korrigiert.

Edit3: targets.getAttribute("data-path") liefert immer nur den Wert der Eigenschaft "data-path" des ersten observierten Objekts. Das ist mal die Quintessenz des Debuggings. Nur fehlen mir gerade Ideen, wie ich beim zweiten Bild den Wert von "data-path" des zweiten Bilds, bis n Bilder dann halt, einfüllen kann. So wie es scheint, kommt das Script nur beim ersten durchlauf in if(entry.isIntersecting) { rein.
 
Zuletzt bearbeitet:
So. Ich hab's. Danke, dass ich hier laut denken durfte. Wie soll ich auch wissen, was ich denke, bevor ich höre, was ich sage ;) Anbei mein Schnippsel:

Javascript:
    var targets = [
        Array.from(document.querySelectorAll(".imgTrigger")),
    ].flat();
    const bookImg = document.querySelector(".bookImg");

    var switchImage = function(entries, observer) {
        entries.forEach((entry, i) => {
            if(entry.isIntersecting) {
                console.log(entry.target.getAttribute("data-path"));
                bookImg.setAttribute("src", entry.target.getAttribute("data-path")); //hatte hier nicht korrekt zugegriffen
                bookImg.classList.remove("hidden");
            }else{
                bookImg.setAttribute("src", "");
                bookImg.classList.add("hidden");
            }
        });
    };

    const objOptions = {
        root: document.getElementById("scrollboxParent"),
        threshold: 1,
        rootMargin: "0px",
    };
   
    const imgObserver = new IntersectionObserver(switchImage, objOptions);

    targets.forEach((target) => imgObserver.observe(target));
Ganz schön viel Arbeit, sich sowas wiedermal beizubringen :) Vielen Dank Sempervivum.
 
Super, dass Du selbst den Fehler finden konntest. Ich war da auch dran und musste mir zunächst Klarheit verschaffen, was in den entries steckt. Und der Kern war, dass es nur die Elemente sind, die gerade in den Viewport rein- oder rausgehen. Deshalb funktionierte der Zugriff mit dem Index nicht.
 
Sehr lieb von dir, dass du mich auf die richtige Spur gebracht und supported hast. Aller Anfang ist schwer und vermutlich war das Thema nicht so einsteigergerecht für einen, der noch kaum was mit JS zu tun gehabt hat. Macht aber Spass und das hier hat mir mal wieder gezeigt, wie wichtig ein anständiger Debugger ist :)

Jetzt muss ich nur noch das Problem lösen, dass das Bild, das beim Laden des Viewportes gleich erscheinen sollte, ebenfalls hidden ist, da ich die Bilder ja auf hidden gesetzt habe, um ein Aufploppen bei Laden zu verhindern. Aber das mach ich dann mal ausgeruht :)
 
Der Intersection-Observer ist schon etwas fortgeschrittener und ich bin erstaunt, dass Du als Einsteiger da so schnell hinein gekommen bist!
 
Hatte heute fast den ganzen Tag Zeit, da ich 11 Tag am Stück gearbeitet hatte, heute frei war und die Kinder betreut waren. Ausserdem habe ich sehr viel in den Dokumentationen gelesen und mit Tutorials herumhantiert. Das, was ich geschrieben habe, ist eigentlich einfach ein Konglomerat von Werken verschiedener Autoren :)
 
Zurück