Przechowuj przepełnienie div przewiń do dołu, chyba że użytkownik przewinie w górę


224

Mam div, który ma tylko 300 pikseli, i chcę, aby przy ładowaniu strony przewijał się na dół zawartości. Ten div ma zawartość dodawaną dynamicznie i musi być przewijany do końca. Teraz, jeśli użytkownik zdecyduje się przewinąć w górę, nie chcę, aby przeskakiwał z powrotem na dół, dopóki użytkownik nie przewinie do końca

Czy jest możliwe, aby div, który pozostanie przewinięty do dołu, chyba że użytkownik przewinie w górę, a kiedy użytkownik przewinie z powrotem do dołu, musi pozostać na dole, nawet po dodaniu nowej zawartości dynamicznej. Jak bym to stworzył.


1
użyj css position top trzymaj go na dole {position : relative; bottom:0;}. Usuń właściwość css po przewinięciu przez użytkownika.
— TCHdvlp

skoro nie przyjąłeś odpowiedzi, chcę zapytać: czy to zadziałało dla ciebie?
— Mr.Manhattan

4
Brzmi jak chatbox, który chcesz osiągnąć
— Thielicious

1
Aby poznać nowe pytanie, wypróbuj css snap w 2020 roku .
— wener

Odpowiedzi:


136

To może ci pomóc:

var element = document.getElementById("yourDivID");
element.scrollTop = element.scrollHeight;

[EDYCJA], aby dopasować komentarz ...

function updateScroll(){
    var element = document.getElementById("yourDivID");
    element.scrollTop = element.scrollHeight;
}

za każdym razem, gdy dodawana jest treść, wywołaj funkcję updateScroll () lub ustaw licznik czasu:

//once a second
setInterval(updateScroll,1000);

jeśli chcesz zaktualizować TYLKO, jeśli użytkownik się nie przeprowadził:

var scrolled = false;
function updateScroll(){
    if(!scrolled){
        var element = document.getElementById("yourDivID");
        element.scrollTop = element.scrollHeight;
    }
}

$("#yourDivID").on('scroll', function(){
    scrolled=true;
});

3
To dobrze przewiń go do dołu przy ładowaniu strony, ale muszę pozostać na dole, gdy dodawana jest zawartość dynamiczna, chyba że użytkownik przewinął w górę.
— Robert E. McIntosh

12
O ile wiem, nie włącza ponownie dynamicznego przewijania, gdy użytkownik przewija z powrotem na dół ...
— TvE

@TvE, czy nie można dodać tego wsparcia?
— Barkermn01,

6
Złe rozwiązanie. Nie ma powodu, aby dodawać setIntervaldo tego łagodnego problemu.
— etancryst

6
@ethancrist jednak nie oferujesz żadnej alternatywy ... wzrusza ramionami.
— Jarett Lloyd,

180

Byłem w stanie uzyskać to działa tylko z CSS.

Sztuką jest użycie display: flex;iflex-direction: column-reverse;

Przeglądarka traktuje dno jak górę. Zakładając, że przeglądarki, na które jesteś celem wsparcia flex-box, jedynym zastrzeżeniem jest to, że znaczniki muszą być w odwrotnej kolejności.

Oto działający przykład. https://codepen.io/jimbol/pen/YVJzBg


42
Możesz obejść się przy konieczności odwrócenia zawartości, dodając dodatkowe opakowanie i nakładając overflow:auto; display:flex; flex-direction:column-reverse;na zewnętrzne opakowanie zamiast wewnętrznego opakowania.
— Nathan Arthur

6
prawdopodobnie najlepsze rozwiązanie, ponieważ nie wymaga javascript.
— Amit Kumar Khare

3
@NathanArthur u da real mvp
— php_nub_qq

13
@NathanArthur W rzeczywistości, jeśli dodasz div pod kontenerem, aby cofnąć wszystko: codepen.io/anon/pen/pdrLEZ
— Coo

6
Niestety to rozwiązanie nie działa w przeglądarce Firefox :(
— Stuart

166

Właśnie to zaimplementowałem i być może możesz użyć mojego podejścia.

Powiedzmy, że mamy następujący kod HTML:

<div id="out" style="overflow:auto"></div>

Następnie możemy sprawdzić, czy przewinął do dołu za pomocą:

var out = document.getElementById("out");
// allow 1px inaccuracy by adding 1
var isScrolledToBottom = out.scrollHeight - out.clientHeight <= out.scrollTop + 1;

scrollHeight daje wysokość elementu, w tym każdy niewidoczny obszar z powodu przepełnienia. clientHeight podaje wysokość CSS lub, mówiąc inaczej, rzeczywistą wysokość elementu. Obie metody zwracają wysokość bez margin, więc nie musisz się o to martwić. scrollTop podaje pozycję przewijania w pionie. 0 to góra, a max to scrollHeight elementu minus jego wysokość. Podczas korzystania z paska przewijania może być trudno (dla mnie było to w Chrome), aby pasek przewijania znalazł się na samym dole. więc rzuciłem niedokładność 1px. Tak isScrolledToBottombędzie, nawet jeśli pasek przewijania znajduje się 1 piksel od dołu. Możesz ustawić to, co ci się podoba.

Następnie wystarczy po prostu ustawić scrollTop elementu na dole.

if(isScrolledToBottom)
    out.scrollTop = out.scrollHeight - out.clientHeight;

Zrobiłem dla ciebie skrzypce, aby pokazać koncepcję: http://jsfiddle.net/dotnetCarpenter/KpM5j/

EDYCJA: Dodano fragment kodu, aby wyjaśnić, kiedy isScrolledToBottomjest true.

Przyklej pasek przewijania do dołu

const out = document.getElementById("out")
let c = 0

setInterval(function() {
    // allow 1px inaccuracy by adding 1
    const isScrolledToBottom = out.scrollHeight - out.clientHeight <= out.scrollTop + 1

    const newElement = document.createElement("div")

    newElement.textContent = format(c++, 'Bottom position:', out.scrollHeight - out.clientHeight,  'Scroll position:', out.scrollTop)

    out.appendChild(newElement)

    // scroll to bottom if isScrolledToBottom is true
    if (isScrolledToBottom) {
      out.scrollTop = out.scrollHeight - out.clientHeight
    }
}, 500)

function format () {
  return Array.prototype.slice.call(arguments).join(' ')
}
#out {
    height: 100px;
}
<div id="out" style="overflow:auto"></div>
<p>To be clear: We want the scrollbar to stick to the bottom if we have scrolled all the way down. If we scroll up, then we don't want the content to move.
</p>


22
To właściwie jedyne rozwiązanie, które spełnia postawione pytanie. I powinien być oznaczony jako poprawna odpowiedź.
— preezzzy

1
@dotnetCarpenter: Wygląda mi na to, że potrzebujesz if(!isScrolledToBottom): test wygląda dla mnie źle (i nie działał w moim kodzie, dopóki go nie naprawiłem).
— luskwater

1
@luskwater czy możesz podać fsfiddle ze swoją poprawką? Nie rozumiem problemu z out.scrollHeight - out.clientHeight <= out.scrollTop + 1. Czy używasz wypełniania w swoim CSS?
— dotnetCarpenter,

2
Właśnie tego szukałem. I to jest odpowiedź na zadane pytanie OP. Dzięki dotnetCarperter.
— Luis Menjivar,

1
Jeśli ktoś dostaje 0, gdy wywołuje scrollTop, sugeruję użycie document.getScrollingElementzgodnie z sugestią tutaj: stackoverflow.com/questions/36227559/scrolltop-always-returns-0/…
— Dane Jordan

29
$('#yourDiv').scrollTop($('#yourDiv')[0].scrollHeight);

Demo na żywo: http://jsfiddle.net/KGfG2/


4
To dobrze przewiń go do dołu przy ładowaniu strony, ale muszę pozostać na dole, gdy dodawana jest zawartość dynamiczna, chyba że użytkownik przewinął w górę.
— Robert E. McIntosh

To działa idealnie. Aktualizuję zawartość dynamiczną, a przewijanie jest zawsze na dole.
— Andy Bajka

14
$('#div1').scrollTop($('#div1')[0].scrollHeight);

Or animated:

$("#div1").animate({ scrollTop: $('#div1')[0].scrollHeight}, 1000);

1
To dobrze przewiń go do dołu przy ładowaniu strony, ale muszę pozostać na dole, gdy dodawana jest zawartość dynamiczna, chyba że użytkownik przewinął w górę.
— Robert E. McIntosh

To nie działa, gdy div rośnie dużo przy pierwszym strzale. na przykład w Angular-js, reaguj js, ładowanie szablonu Meteor Blaze, to nie zadziała.
— Ankur Soni

To zadziałało dla mnie. Myślę, że to działa dobrze, jeśli div będzie utrzymywać stałą wysokość. Nie testowałem tego z dynamicznymi wysokościami.
— doij790

11

W 2020 r. Możesz użyć przyciągania css , ale przed Chrome 81 zmiana układu nie spowoduje ponownego przyciągania , interfejs użytkownika czatu w czystym css działa w Chrome 81, możesz także sprawdzić Czy mogę użyć przyciągania CSS .

To demo przyciągnie ostatni element, jeśli jest widoczny, przewiń w dół, aby zobaczyć efekt.

.container {
  overflow-y: scroll;
  overscroll-behavior-y: contain;
  scroll-snap-type: y mandatory;
}

.container > div > div:last-child {
  scroll-snap-align: end;
}

.container > div > div {
  background: lightgray;
  height: 3rem;
  font-size: 1.5rem;
}
.container > div > div:nth-child(2n) {
  background: gray;
}
<div class="container" style="height:6rem">
<div>
<div>1</div>
<div>2</div>
<div>3</div>
<div>4</div>
<div>5</div>
</div>
</div>

wprowadź opis zdjęcia tutaj


5

.cont{
height: 100px;
overflow-x: hidden;
overflow-y: auto;
transform: rotate(180deg);
direction:rtl;
text-align:left;
}
ul{
overflow: hidden;
transform: rotate(180deg);
}
<div class="cont"> 
 <ul>
   <li>0</li>
   <li>1</li>
   <li>2</li>
   <li>3</li>
   <li>4</li>
   <li>5</li>
   <li>6</li>
   <li>7</li>
   <li>8</li>
   <li>9</li>
   <li>10</li>  
 </ul>
</div>

  1. Run code snippetzobaczyć efekt. (PS: Jeśli Run code snippetnie działa, spróbuj tego: https://jsfiddle.net/Yeshen/xm2yLksu/3/ )

  2. Jak to działa:

Domyślnym przepełnieniem jest przewijanie od góry do dołu.

transform: rotate(180deg) może powodować przewijanie lub ładowanie bloku dynamicznego od dołu do góry.

  1. Oryginalny pomysł:

https://blog.csdn.net/yeshennet/article/details/88880252


Dodaj dodatkowe wyjaśnienie, w jaki sposób Twój kod rozwiązuje pytanie OP
— jro

1, dodał dodatkowe wprowadzenie. 2, proszę Run code snippetbezpośrednio zobaczyć efekt.
— yisheng wu

Przycisk fragmentu kodu uruchomienia nie jest dla mnie wyświetlany. Sprawdź swoje formatowanie
— Jro

To wspaniale. Dołącz link do swojej odpowiedzi
— jro

2
Bardzo kreatywne rozwiązanie. Odwraca jednak normalne działanie kółka przewijania myszy. Aby przejść w górę, muszę przewinąć „w dół” i odwrotnie.
— mfluehr

3
$('#yourDivID').animate({ scrollTop: $(document).height() }, "slow");
return false;

Spowoduje to obliczenie pozycji ScrollTop z wysokości #yourDivIDkorzystania z $(document).height()właściwości, dzięki czemu nawet jeśli zawartość dynamiczna zostanie dodana do div, scroller będzie zawsze w dolnej pozycji. Mam nadzieję że to pomoże. Ale ma też mały błąd, nawet jeśli przewiniemy w górę i opuszczymy wskaźnik myszy z rolki, automatycznie dojdzie do dolnej pozycji. Jeśli ktoś może to naprawić, to też będzie miło.


2
//Make sure message list is scrolled to the bottom
var container = $('#MessageWindowContent')[0];
var containerHeight = container.clientHeight;
var contentHeight = container.scrollHeight;

container.scrollTop = contentHeight - containerHeight;

Oto moja wersja oparta na odpowiedzi dotnetCarpenter. Moje podejście jest czystym jQuery i zmieniłem nazwy zmiennych, aby wszystko było trochę jaśniejsze. Dzieje się tak, gdy wysokość zawartości jest większa niż kontener przewijamy o dodatkową odległość w dół, aby osiągnąć pożądany rezultat.

Działa w IE i chrome ..


2

Odpowiedź Jima Halla jest lepsza, ponieważ chociaż nie przewija się ona do dołu, gdy jesteś przewijany w górę, jest to również czysty CSS.

Niestety, nie jest to stabilne rozwiązanie: w chrome (prawdopodobnie z powodu problemu 1-px opisanego przez dotnetCarpenter powyżej) scrollTopzachowuje się niedokładnie o 1 piksel, nawet bez interakcji użytkownika (po dodaniu elementu). Możesz ustawić scrollTop = scrollHeight - clientHeight, ale to utrzyma div na miejscu, gdy zostanie dodany inny element, inaczej funkcja „trzymaj się dołu” już nie działa.

Krótko mówiąc, dodanie niewielkiej ilości Javascript (westchnień) naprawi to i spełni wszystkie wymagania:

Coś w stylu https://codepen.io/anon/pen/pdrLEZ this (przykład autorstwa Coo), a po dodaniu elementu do listy, również:

container = ...
if(container.scrollHeight - container.clientHeight - container.scrollTop <= 29) {
    container.scrollTop = container.scrollHeight - container.clientHeight;
}

gdzie 29 to wysokość jednej linii.

Tak więc, gdy użytkownik przewinie w górę o pół linii (jeśli to w ogóle możliwe?), JavaScript zignoruje go i przewinie w dół. Ale wydaje mi się, że jest to nieistotne. I naprawia Chrome 1 px rzeczy.


2

Oto rozwiązanie oparte na poście na blogu autorstwa Ryana Hunta . Zależy to od overflow-anchorwłaściwości CSS, która przypina pozycję przewijania do elementu na dole przewijanej treści.

const messages = [
  'Expect rain today.',
  'Tomorrow will be sunny.',
  'Snow is coming next week.',
  'Hailstorms are imminent.',
];

function addMessage() {
  const $message = document.createElement('div');
  $message.className = 'message';
  $message.innerText = messages[(Math.random() * messages.length) | 0];
  $messages.insertBefore($message, $anchor);

  // Trigger the scroll pinning when the scroller overflows
  if (!overflowing) {
    overflowing = isOverflowing($scroller);
    $scroller.scrollTop = $scroller.scrollHeight;
  }
}

function isOverflowing($el) {
  return $el.scrollHeight > $el.clientHeight;
}

const $scroller = document.querySelector('.scroller');
const $messages = document.querySelector('.messages');
const $anchor = document.querySelector('.anchor');
let overflowing = false;

setInterval(addMessage, 1000);
.scroller {
  overflow: auto;
  height: 90vh;
  max-height: 11em;
  background: #555;
}

.messages > * {
  overflow-anchor: none;
}

.anchor {
  overflow-anchor: auto;
  height: 1px;
}

.message {
  margin: .3em;
  padding: .5em;
  background: #eee;
}
<section class="scroller">
  <div class="messages">
    <div class="anchor"></div>
  </div>
</section>

Pamiętaj, że overflow-anchorobecnie nie działa w Safari ani Edge, więc to rozwiązanie nie działa obecnie we wszystkich przeglądarkach.


1

Możesz użyć czegoś takiego,

var element = document.getElementById("yourDivID");
window.scrollTo(0,element.offsetHeight);

Wyjaśnij to, proszę!
— Szabolcs Páll

1. scrollTo to metoda, która przewija całe okno do określonych współrzędnych. 2. offset zapewnia wysokość elementu, dzięki czemu druga linia powyższego kodu przewija okno w dół podczas przypisywania czegoś.
— Yashsz Chauhan

0

Oto jak do tego podszedłem. Mój div ma wysokość 650px. Zdecydowałem, że jeśli wysokość przewijania mieści się w granicach 150 pikseli od dołu, to przewiń automatycznie. W przeciwnym razie pozostaw to użytkownikowi.

if (container_block.scrollHeight - container_block.scrollTop < 800) {
                    container_block.scrollTo(0, container_block.scrollHeight);
}
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.