webentwicklung-frage-antwort-db.com.de

jquery - das Fenster daran hindern, die Bildlaufposition zu ändern, während Elemente einer Liste vorangestellt werden?

Ich habe eine Seite, auf der Nachrichten angezeigt werden, und ich möchte, dass sie wie Facebook funktioniert, jedoch ohne den Lazy Loader. Meldungen werden in chronologischer Reihenfolge angezeigt, zuletzt zuletzt.

Meine Nachrichtenliste ist anfangs mit x Anzahl der letzten Nachrichten gefüllt und das Fenster wird nach unten gescrollt. Wenn der Benutzer mit dem Lesen des Threads beginnt, liest er von unten nach oben. Wenn sie an die Spitze gelangen, können sie weitere Nachrichten laden ... Ich lasse sie auf einen Button klicken ... Facebook hat einen Lazy Loader. Neue Nachrichten werden der Liste vorangestellt.

Problem: Wenn die neuen Nachrichten vorangestellt werden, werden die vorhandenen Nachrichten nach unten gedrückt, wodurch der Benutzer seinen "Sichtbereich" verliert. Wie kann ich die aktuelle Ansichtsposition des Benutzers beibehalten, wenn ich die neuen Nachrichten hinzufüge? Öffnen Sie zum Beispiel einen langen Nachrichtenthread in Facebook, scrollen Sie nach oben, sodass neue Nachrichten hinzugefügt werden ... Ihr Ansichtsstandort ändert sich nicht, obwohl sich die Bildlaufposition ändert.

29
Redtopia

Speichern Sie einen Verweis auf die erste Nachricht, bevor Sie neue Nachrichten voranstellen, und setzen Sie nach dem vorherigen Schreiben den Bildlauf auf den Versatz dieser Nachricht:

$(document).on('scroll', function() {
    var scroll = $(document).scrollTop();
    if (scroll < 1) {
        // Store eference to first message
        var firstMsg = $('.message:first');

        // Prepend new message here (I'm just cloning...)
        $('body').prepend(firstMsg.clone());

        // After adding new message(s), set scroll to position of
        // what was the first message
        $(document).scrollTop(firstMsg.offset().top);
    }
});

Demo: http://jsfiddle.net/GRnQY/

Edit: Ich habe bemerkt, dass Sie es mit einem Button wollten. Möglicherweise müssen Sie ein wenig mehr rechnen:

$(document).on('click', '#loadMore', function() {
    var firstMsg = $('.message:first');

    // Where the page is currently:
    var curOffset = firstMsg.offset().top - $(document).scrollTop();

    // Prepend
    firstMsg.before(firstMsg.clone());

    // Offset to previous first message minus original offset/scroll
    $(document).scrollTop(firstMsg.offset().top-curOffset);
});

Demo: http://jsfiddle.net/GRnQY/5/

49
Jeff B

Es ist keine Notwendigkeit für jQuery hier, überprüfen Sie die Elemente in scrollHeight auf Änderungen und passen Sie den scrollTop entsprechend an, dh:

var lastScrollHeight = el.scrollHeight;
for(var n=0; n<10; n++){
    // Prepend here...
}
var scrollDiff = el.scrollHeight - lastScrollHeight;
el.scrollTop += scrollDiff;

Demo

http://jsfiddle.net/fkqqv28e/

jQuery

Um auf den nativen DOM-Knoten aus einer jQuery-Sammlung zuzugreifen, verwenden Sie den Array-Zugriff. dh:

var lastScrollHeight = $('#myElement')[0].scrollHeight;
for(var n=0; n<10; n++){
    $('#myElement').prepend('<div>prepended '+Math.random()+'</div>');
}
var scrollDiff = $('#myElement')[0].scrollHeight - lastScrollHeight;
$('#myElement')[0].scrollTop += scrollDiff;
7
oodavid

Einige Leute, die hierher kommen, möchten vielleicht nur Inhalte hinzufügen, ohne dass der aktuelle Fokus herumspringt. Wenn Sie die Demo von Jeff B oben ändern, um das Klickereignisziel zu verwenden, wird diese Redewendung tragbarer:

someButton.on('click', function() {
    var curOffset = $(this).offset().top - $(document).scrollTop();
    // add content to your heart's content.
    $(document).scrollTop($(this).offset().top-curOffset);
});

c.f. http://jsfiddle.net/bwz8uLvt/1/ (Variante von Jeff Bs Demo oben, jedoch mit der Schaltfläche [Mehr hinzufügen] an einer beliebigen Stelle der Seite).

3
ericP

Hier ist ein einfacher Trick, der für mich funktioniert hat:

// divWithTheScroll.prependElement...
divWithTheScroll.scrollTop += newlyPrependedElement.scrollHeight;
1
Lacho Tomov

Sie können die Bildlaufposition auch basierend auf dem Versatz zum unteren Rand der Seite/des Elements beibehalten.

var ScrollFromBottom = $(document).height() - $(window).scrollTop();

//ajax - add messages -- geenrate html code then add to dom

//set scroll position
$(window).scrollTop($(document).height() - ScrollFromBottom);
0
Dany Gauthier

Ich bin gerade auf eine Variation davon gestoßen. Ich habe eine große Anzahl von Elementen losgelöst, bearbeitet und dann wieder angefügt. Dies wird in Chrome nicht synchron ausgeführt, sodass ich $ el.scrollTop (oldval) nicht zuverlässig festlegen konnte. Ich fand diese Lösung für mich.

// get old scroll top of '#sub_elem'
oldScrollTop = $('#sub_elem).scrollTop();

// detach
$els = $('#sub_elem').detach();

// complex processing on #sub_elem
// goes here

// attach
$('#main_el').attach($els);

// problem- always scrolls #sub_elem back to the top
// attempt #1: $('#sub_elem').scrollTop(oldScrollTop); // fails on mac Chrome
// attempt #2: use instant animation.  this works on mac Chrome
if (oldScrollTop) {
    $('#sub_elem').animate({
        scrollTop: oldScrollTop
    }, 0);
}
0
xeo