Jquery - сохранить окно от изменения положения прокрутки во время добавления элементов в список?
У меня есть страница, отображающая сообщения, и я хочу, чтобы она работала так же, как и Facebook, но без ленивого загрузчика. Сообщения отображаются в хронологическом порядке, последние последние.
В моем списке сообщений сначала заполняется x число последних сообщений, а окно прокручивается вниз. Когда пользователь начинает читать поток, они читают снизу вверх. Если они доберутся до вершины, они могут загружать больше сообщений... Я заставляю их нажимать кнопку... facebook имеет ленивый загрузчик. Новые сообщения добавляются в список.
Проблема. По мере добавления новых сообщений существующие сообщения выталкиваются вниз, заставляя пользователя потерять свое "просматриваемое" место. Как я могу сохранить текущую позицию пользователя во время добавления новых сообщений? Например, откройте длинный поток сообщений в facebook, прокрутите вверх, в результате чего новые сообщения будут добавлены... ваше местоположение просмотра не изменяется, даже если позиция прокрутки делает.
Ответы
Ответ 1
Сохраните ссылку на первое сообщение перед добавлением новых сообщений, и после того, как вы добавили, установите прокрутку в смещение этого сообщения:
$(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);
});
Демо: http://jsfiddle.net/GRnQY/5/
Ответ 2
Здесь нет необходимости в jQuery, просто проверьте изменения элементов scrollHeight и отредактируйте scrollTop соответственно, то есть:
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
Чтобы получить доступ к исходному DOM node из коллекции jQuery, используйте доступ к массиву; то есть:
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;
Ответ 3
Некоторые люди, приезжающие сюда, могут просто захотеть добавить контент без текущей фокусировки. Изменение демоверсии Jeff B выше, чтобы использовать цель клика, делает эту идиому более переносимой:
someButton.on('click', function() {
var curOffset = $(this).offset().top - $(document).scrollTop();
// add content to your heart content.
$(document).scrollTop($(this).offset().top-curOffset);
});
c.f. http://jsfiddle.net/bwz8uLvt/1/ (вариант демонстрации Jeff B выше, но с кнопкой [добавить еще] в произвольной точке страницы).
Ответ 4
Я просто пробежал вариацию этого. я отделил большое количество элементов, обработал их, а затем снова привязал их. это не завершается синхронно в 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);
}
Ответ 5
Вы также можете сохранить положение прокрутки на основе смещения в нижней части страницы/элемента.
var ScrollFromBottom = $(document).height() - $(window).scrollTop();
//ajax - add messages -- geenrate html code then add to dom
//set scroll position
$(window).scrollTop($(document).height() - ScrollFromBottom);