408 Stimmen

Halten Sie das Überlauf-Div am unteren Rand gescrollt, es sei denn, der Benutzer scrollt nach oben.

Ich habe ein div, das nur 300 Pixel groß ist, und ich möchte, dass es beim Laden der Seite zum Ende des Inhalts scrollt. Dieses div hat dynamisch hinzugefügten Inhalt und muss immer ganz unten bleiben. Wenn der Benutzer sich jedoch entscheidet, nach oben zu scrollen, möchte ich nicht, dass es sofort wieder nach unten springt, bis der Benutzer wieder ganz nach unten scrollt.

Ist es möglich, ein div zu haben, das unten bleibt, es sei denn, der Benutzer scrollt nach oben, und wenn der Benutzer wieder nach unten scrollt, muss es sich selbst unten halten, selbst wenn neuer dynamischer Inhalt hinzugefügt wird. Wie könnte ich das erreichen?

1voto

Jam Roll Punkte 13

Das Folgende tut, was du brauchst (ich habe mein Bestes gegeben, mit vielen Google-Suchen auf dem Weg):

    // kein jQuery oder anderer Wahnsinn. Einfach
    // geradlinige Vanilla-JavaScript-Funktionen
    // um den Inhalt eines divs zum unteren Rand zu scrollen
    // wenn der Benutzer nicht nach oben gescrollt hat. Inklusive
    // eines anklickbaren "Alerts", wenn sich der "Inhalt" ändert.

    // dies sollte für jede Art von Inhalt funktionieren
    // sei es Bilder, Links oder einfacher Text
    // füge einfach das neue Element an
    // das div an, und der Rest wird wie beschrieben behandelt.

    let scrolled = false; // am Boden?
    let scrolling = false; // im nächsten Nachrichten-Scrollen?
    let listener = false; // hat das Element einen Content-Changed-Listener?
    let contentChanged = false; // ziemlich offensichtlich
    let alerted = false; // weniger offensichtlich

    function innerHTMLChanged() {
      // das ist hier für den Fall, dass wir
      // anpassen möchten, was hier passiert.
      // für jetzt nur:
      contentChanged = true;
    }

    function scrollToBottom(id) {
      if (!id) { id = "scrollable_element"; }
      let DEBUG = 0; // auf 1 ändern und Konsole öffnen
      let dstr = "";

      let e = document.getElementById(id);
      if (e) {
        if (!listener) {
          dstr += "content changed listener not active\n";
          e.addEventListener("DOMSubtreeModified", innerHTMLChanged);
          listener = true;
        } else {
          dstr += "content changed listener active\n";
        }
        let height = (e.scrollHeight - e.offsetHeight); // das ist nicht perfekt
        let offset = (e.offsetHeight - e.clientHeight); // und behebt dies das? scheint so...
        let scrollMax = height + offset;

        dstr += "offsetHeight: " + e.offsetHeight + "\n";
        dstr += "clientHeight: " + e.clientHeight + "\n";
        dstr += "scrollHeight: " + e.scrollHeight + "\n";
        dstr += "scrollTop: " + e.scrollTop + "\n";
        dstr += "scrollMax: " + scrollMax + "\n";
        dstr += "offset: " + offset + "\n";
        dstr += "height: " + height + "\n";
        dstr += "contentChanged: " + contentChanged + "\n";

        if (!scrolled && !scrolling) {
          dstr += "Benutzer hat nicht gescrollt\n";
          if (e.scrollTop != scrollMax) {
            dstr += "Scrollen nicht am Ende\n";
            e.scroll({
              top: scrollMax,
              left: 0,
              behavior: "auto"
            })
            e.scrollTop = scrollMax;
            scrolling = true;
          } else {
            if (alerted) {
              dstr += "Alarm existiert\n";
            } else {
              dstr += "Alarm existiert nicht\n";
            }
            if (contentChanged) { contentChanged = false; }
          }
        } else {
          dstr += "Benutzer hat sich vom Ende entfernt gescrollt\n";
          if (!scrolling) {
            dstr += "nicht automatisch scrollen\n";

            if (e.scrollTop >= scrollMax) {
              dstr += "Scrollen am Ende\n";
              scrolled = false;

              if (alerted) {
                dstr += "Alarm existiert\n";
                let n = document.getElementById("alert");
                n.remove();
                alerted = false;
                contentChanged = false;
                scrolled = false;
              }
            } else {
              dstr += "Scrollen nicht am Ende\n";
              if (contentChanged) {
                dstr += "Inhalt geändert\n";
                if (!alerted) {
                  dstr += "Alarm wird nicht angezeigt\n";
                  let n = document.createElement("div");
                  e.append(n);
                  n.id = "alarm";
                  n.style.position = "absolute";
                  n.classList.add("normal-panel");
                  n.classList.add("klickbar");
                  n.classList.add("blinkend");
                  n.innerHTML = "neuer Inhalt!";

                  let nposy = parseFloat(getComputedStyle(e).height) + 18;
                  let nposx = 18 + (parseFloat(getComputedStyle(e).width) / 2) - (parseFloat(getComputedStyle(n).width) / 2);
                  dstr += "nposx: " + nposx + "\n";
                  dstr += "nposy: " + nposy + "\n";
                  n.style.left = nposx;
                  n.style.top = nposy;

                  n.addEventListener("click", () => {
                    dstr += "Alarm löschen\n";
                    scrolled = false;
                    alerted = false;
                    contentChanged = false;
                    n.remove();
                  });

                  alerted = true;
                } else {
                  dstr += "Alarm bereits angezeigt\n";
                }
              } else {
                alerted = false;
              }
            }
          } else {
            dstr += "automatisches Scrollen\n";
            if (e.scrollTop >= scrollMax) {
              dstr += "Scrollen beendet";
              scrolling = false;
              scrolled = false;
            } else {
              dstr += "immer noch am Scrollen...\n";
            }
          }
        }
      }

      if (DEBUG && dstr) console.log("stb:\n" + dstr);

      setTimeout(() => { scrollToBottom(id); }, 50);
    }

    function scrollMessages(id) {
      if (!id) { id = "scrollable_element"; }
      let DEBUG = 1;
      let dstr = "";

      if (scrolled) {
        dstr += "bereits gescrollt";
      } else {
        dstr += "gescrollt";
        scrolled = true;
      }
      dstr += "\n";

      if (contentChanged && alerted) {
        dstr += "Inhalt geändert, und Alarm ausgelöst\n";
        let n = document.getElementById("alert");
        if (n) {
          dstr += "Alarm-Div existiert\n";
          let e = document.getElementById(id);
          let nposy = parseFloat(getComputedStyle(e).height) + 18;
          dstr += "nposy: " + nposy + "\n";
          n.style.top = nposy;
        } else {
          dstr += "Alarm-Div existiert nicht!\n";
        }
      } else {
        dstr += "Inhalt NICHT geändert, und kein Alarm ausgelöst";
      }

      if (DEBUG && dstr) console.log("sm: " + dstr);
    }

    setTimeout(() => { scrollToBottom("messages"); }, 1000);

    /////////////////////
    // HILFSFUNKTION
    //   simuliert das Hinzufügen von dynamischem Inhalt zum "chat" div
    let count = 0;
    function addContent() {
      let e = document.getElementById("messages");
      if (e) {
        let br = document.createElement("br");
        e.append("test " + count);
        e.append(br);
        count++;
      }
    }

button {
  border-radius: 5px;
}

#container {
  padding: 5px;
}

#messages {
  background-color: blue;
  border: 1px inset black;
  border-radius: 3px;
  color: white;
  padding: 5px;
  overflow-x: none;
  overflow-y: auto;
  max-height: 100px;
  width: 100px;
  margin-bottom: 5px;
  text-align: left;
}

.bordered {
  border: 1px solid black;
  border-radius: 5px;
}

.inline-block {
  display: inline-block;
}

.centered {
  text-align: center;
}

.normal-panel {
  background-color: #888888;
  border: 1px solid black;
  border-radius: 5px;
  padding: 2px;
}

.klickbar {
  cursor: pointer;
}

    test
    test
    test
    test
    test
    test
    test
    test
    test
    test

  Inhalt hinzufügen

Hinweis: Möglicherweise müssen Sie die Position des Alerts (nposx und nposy) in den Funktionen scrollToBottom und scrollMessages an Ihre Bedürfnisse anpassen...

1voto

Ahmet Emrebas Punkte 167

Es gibt nativen Support für dieses Problem.

Es gibt eine Methode namens *.scrollIntoView. Nachdem diese Methode einmal ausgeführt wurde, bleibt der Container am unteren Rand gescrollt. Auch nach Hinzufügen neuer Inhalte zum Container scrollt er nach unten.

import {
  AfterViewInit,
  Directive,
  ElementRef,
} from '@angular/core';

@Directive({
  selector: '[aeScrollIntoView]',
})
export class ScrollIntoViewDirective implements AfterViewInit {
  constructor(private readonly el: ElementRef) {}
  ngAfterViewInit(): void {
    this.el.nativeElement.scrollIntoView({ behavior: 'smooth' });
  }
}

0voto

Raj Punkte 71

Ich habe die Lösungen von dotnetCarpenter und Mr.Manhattan kombiniert. Aber ich hatte auch Probleme mit der Scrollleiste, die sich von alleine bewegt, wenn der Benutzer zoomt oder das Fenster aufgrund von Änderungen in der Textumwicklung neu dimensioniert wird. Zum Beispiel, wenn das div responsiv ist. Daher ist dies die Lösung, die ich gefunden habe, um die Scrollleiste am unteren Rand zu halten, wenn das Fenster neu dimensioniert wird.

HTML

Javascript

var scrolledToBottom = true;
var lastWidth, lastHeight;

$('#scroll-div').on('scroll', (e) => {
  var div = e.target;

  if(div.scrollHeight - div.clientHeight <= div.scrollTop + 1) 
    scrolledToBottom = true; 
  // Nur annehmen, dass der Benutzer die Scrollleiste bewegt hat, wenn das Fenster nicht neu dimensioniert/vergrößert wurde
  else if(lastWidth === div.clientWidth && lastHeight === div.clientHeight) 
    scrolledToBottom = false; 
  else if(scrolledToBottom)
    $(div).scrollTop(div.scrollHeight); // Die Scrollleiste wurde aufgrund von Änderungen in der Größe verschoben, also wieder nach unten bewegen

  lastWidth = div.clientWidth;
  lastHeight = div.clientHeight;
});

$(window).on('resize', () => {
  $('#scroll-div').trigger('scroll'); // Scroll auslösen, falls die Scrollleiste erscheint/verschwindet
});

function addContent() {
  // hier Inhalt hinzufügen

  if(scrolledToBottom) 
    $('#scroll-div').scrollTop($('#scroll-div')[0].scrollHeight);
}

0voto

AndSmith Punkte 751

Ich habe es geschafft, dass es funktioniert. Der Trick besteht darin zu berechnen: (a) die aktuelle Bildlaufposition des Benutzers im div und (b) die Bildlaufhöhe des div, BEVOR das neue Element hinzugefügt wird.

Wenn a === b, wissen wir, dass der Benutzer am Ende ist, bevor das neue Element hinzugefügt wird.

    let div = document.querySelector('div.scrollableBox');

    let span = document.createElement('span');
    span.textContent = 'Hallo';

    let divCurrentUserScrollPosition = div.scrollTop + div.offsetHeight;
    let divScrollHeight = div.scrollHeight;

    // Wir haben die aktuellen Bildlaufpositionen in
    // Variablen gespeichert, daher können wir jetzt das neue Element hinzufügen.
    div.append(span);

    if ((divScrollHeight === divCurrentUserScrollPosition)) {
        // Zum unteren Ende des div scrollen
        div.scrollTo({ left: 0, top: div.scrollHeight });
    }

0voto

Marco Punkte 31

Hier ist, wie ich es angegangen bin. Die Höhe meines Div-Elements beträgt 650px. Ich habe entschieden, dass wenn die Scroll-Höhe innerhalb von 150px vom Ende ist, dann automatisch scrollen. Andernfalls, es dem Benutzer überlassen.

if (container_block.scrollHeight - container_block.scrollTop < 800) {
                    container_block.scrollTo(0, container_block.scrollHeight);
}

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X