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 ノードにアクセスするには、配列アクセスを使用します。すなわち:

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 のデモを変更すると、このイディオムの移植性が向上します。

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 のデモの変形ですが、ページの任意の場所に [さらに追加] ボタンがあります)。

于 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 に答える
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 に答える