jquery-сохранить окно от изменения положения прокрутки при добавлении элементов в список?
У меня есть страница, которая отображает сообщения и я хочу, чтобы работать так же, как Facebook, но не ленивый грузчик. Сообщения отображаются в хронологическом порядке, последние последние.
мой список сообщений изначально заполняется x числом последних сообщений, и окно прокручивается вниз. Когда пользователь начинает читать потоком, они читают снизу вверх. Если они доберутся до вершины, то смогут загрузить больше сообщений... Я заставляю их нажать кнопку... facebook имеет ленивый погрузчик. К списку добавляются новые сообщения.
проблема: по мере добавления новых сообщений существующие сообщения выталкиваются, в результате чего пользователь теряет место "просмотра". Как сохранить текущую позицию представления пользователя при добавлении новых сообщений? Например, откройте длинный поток сообщений в facebook, прокрутите вверх, чтобы добавить новые сообщения... ваше местоположение представления не изменяется, даже если это делает положение прокрутки.
6 ответов
Сохраните ссылку на первое сообщение перед добавлением новых сообщений, а после добавления установите для прокрутки значение смещения этого сообщения:
$(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);
    }
});
демо:http://jsfiddle.net/GRnQY/
редактировать: я заметил, что вы хотели его с кнопки. Возможно, вам придется сделать немного больше математики:
$(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);
});
нет необходимости в jQuery здесь, просто проверьте изменения в элементах scrollHeight и отрегулируйте scrollTop соответственно, т. е.:
var lastScrollHeight = el.scrollHeight;
for(var n=0; n<10; n++){
    // Prepend here...
}
var scrollDiff = el.scrollHeight - lastScrollHeight;
el.scrollTop += scrollDiff;
демо
jQuery
чтобы получить доступ к собственному узлу DOM из коллекции jQuery, используйте array access; ie:
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;
некоторые люди, приходящие сюда, могут просто захотеть добавить контент без текущего фокуса. Изменение демо Джеффа B выше, чтобы использовать цель события click, делает эту идиому более переносимой:
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/ (вариант демонстрации Джеффа Б выше, но с кнопкой [добавить больше] в произвольной точке страницы).
Я только что столкнулся с вариацией этого. я отсоединил большое количество элементов, обработал их и снова присоединил. это не завершается синхронно в Chrome, поэтому я не мог установить $el.scrollTop(oldval) надежно. Я обнаружил, что это решение сработало для меня.
// 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);
}
вы также можете сохранить положение прокрутки на основе смещения в нижней части страницы / элемента.
var ScrollFromBottom = $(document).height() - $(window).scrollTop();
//ajax - add messages -- geenrate html code then add to dom
//set scroll position
$(window).scrollTop($(document).height() - ScrollFromBottom);
вот простой трюк, который сработал для меня:
// divWithTheScroll.prependElement...
divWithTheScroll.scrollTop += newlyPrependedElement.scrollHeight;