jquery - 在将项目添加到列表时保持窗口不改变滚动位置?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/9834143/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
jquery - keep window from changing scroll position while prepending items to a list?
提问by Redtopia
I have a page that displays messages and I want it to work just like Facebook, but without the lazy loader. Messages are displayed in chronological order, most recent last.
我有一个显示消息的页面,我希望它像 Facebook 一样工作,但没有延迟加载程序。消息按时间顺序显示,最近的最后显示。
My message list is initially populated x number of most recent messages, and the window is scrolled to the bottom. When the user starts to read the thread, they read from bottom to top. If they get to the top, they can load more messages... I make them click a button... facebook has a lazy loader. New messages are prepended to the list.
我的消息列表最初填充了 x 条最近的消息,并且窗口滚动到底部。当用户开始阅读线程时,他们会从下到上阅读。如果他们到达顶部,他们可以加载更多消息......我让他们点击一个按钮......facebook有一个懒惰的加载器。新消息被添加到列表中。
Problem: As the new messages are prepended, the existing messages are pushed down, causing the user to lose their "viewing" place. How can I keep the user's current view position as I add the new messages? For an example, open a long message thread in facebook, scroll to the top causing new messages to be added... your view location doesn't change even though the scroll position does.
问题:随着新消息的添加,现有消息被下推,导致用户失去他们的“查看”位置。我如何在添加新消息时保持用户的当前视图位置?例如,在 facebook 中打开一个长消息线程,滚动到顶部导致添加新消息......即使滚动位置发生变化,您的视图位置也不会改变。
回答by Jeff B
Store a reference to the first message before you prepend new messages, and after you prepend, set the scroll to the offset of that message:
在添加新消息之前存储对第一条消息的引用,在添加之后,将滚动设置为该消息的偏移量:
$(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/
演示:http: //jsfiddle.net/GRnQY/
Edit: I noticed you wanted it with a button. You might have to do a little more math:
编辑:我注意到你想要一个按钮。您可能需要做更多的数学运算:
$(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);
});
回答by oodavid
No need for jQuery here, just check for changes in the elements scrollHeight and adjust the scrollTop accordingly, ie:
这里不需要 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
演示
jQuery
jQuery
To access the native DOM node from a jQuery collection, use array access; ie:
要从 jQuery 集合访问本机 DOM 节点,请使用数组访问;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;
回答by ericP
Some folks coming here may just want to add content without the current focus jumping around. Modifying Jeff B's demo above to use the click event target makes this idiom more portable:
一些来到这里的人可能只想添加内容而不需要当前的焦点跳跃。修改上面 Jeff 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/(variant of Jeff B's demo above but with the [add more] button at an arbitrary point in the page).
参见http://jsfiddle.net/bwz8uLvt/1/(上面 Jeff B 演示的变体,但在页面中的任意点有 [add more] 按钮)。
回答by Lacho Tomov
Here's a simple trick that worked for me:
这是一个对我有用的简单技巧:
// divWithTheScroll.prependElement...
divWithTheScroll.scrollTop += newlyPrependedElement.scrollHeight;
回答by Dany Gauthier
You could also keep the scroll position based on the offset to the bottom of the page/element.
您还可以根据到页面/元素底部的偏移量来保持滚动位置。
var ScrollFromBottom = $(document).height() - $(window).scrollTop();
//ajax - add messages -- geenrate html code then add to dom
//set scroll position
$(window).scrollTop($(document).height() - ScrollFromBottom);
回答by xeo
I just ran across a variation of this. i detached a large number of elements, processed them and then attached them again. this doesn't complete synchronously in Chrome so i could not set $el.scrollTop(oldval) reliably. I found this solution worked for me.
我只是遇到了这个的变体。我分离了大量元素,处理它们,然后再次附加它们。这不会在 Chrome 中同步完成,所以我无法可靠地设置 $el.scrollTop(oldval)。我发现这个解决方案对我有用。
// get old scroll top of '#sub_elem'
var oldScrollTop = $('#sub_elem').scrollTop();
// detach
var $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);
}