46

我有一个显示消息的页面,我希望它像 Facebook 一样工作,但没有惰性加载器。消息按时间顺序显示,最近的在最后。

我的消息列表最初填充了 x 条最新消息,并且窗口滚动到底部。当用户开始阅读线程时,他们从下到上阅读。如果他们到达顶部,他们可以加载更多消息......我让他们点击一个按钮...... facebook 有一个惰性加载器。新消息将附加到列表中。

问题:随着新消息的添加,现有消息被下推,导致用户失去“查看”位置。添加新消息时如何保持用户的当前视图位置?例如,在 facebook 中打开一个长消息线程,滚动到顶部导致添加新消息......即使滚动位置发生变化,您的视图位置也不会改变。

4

6 回答 6

68

在添加新消息之前存储对第一条消息的引用,在添加新消息之后,将滚动设置为该消息的偏移量:

$(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/

于 2012-03-23T04:40:23.453 回答
18

这里不需要jQuery,只需检查元素scrollHeight的变化并相应地调整scrollTop,即:

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

演示

http://jsfiddle.net/fkqqv28e/

jQuery

要从 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;
于 2015-11-25T14:15:49.027 回答
6

有些来到这里的人可能只是想添加内容而不转移当前的焦点。将上面 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);
});

cf http://jsfiddle.net/bwz8uLvt/1/(上面 Jeff B 演示的变体,但在页面的任意位置有 [add more] 按钮)。

于 2016-05-14T06:25:19.790 回答
2

您还可以根据到页面/元素底部的偏移量来保持滚动位置。

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

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

//set scroll position
$(window).scrollTop($(document).height() - ScrollFromBottom);
于 2016-09-13T18:49:28.483 回答
2

这是一个对我有用的简单技巧:

// divWithTheScroll.prependElement...
divWithTheScroll.scrollTop += newlyPrependedElement.scrollHeight;
于 2018-09-09T16:55:38.103 回答
0

我刚刚遇到了这个的变体。我分离了大量元素,处理它们,然后再次附加它们。这不会在 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);
}
于 2016-02-20T17:29:18.897 回答