【问题标题】:jquery - keep window from changing scroll position while prepending items to a list?jquery - 在将项目附加到列表时保持窗口不改变滚动位置?
【发布时间】:2012-04-07 17:08:57
【问题描述】:

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

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

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

【问题讨论】:

    标签: jquery list window scroll prepend


    【解决方案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/

    【讨论】:

    • 第二个解决方案太棒了 - 非常感谢,这对于实现类似于 Facebook 消息的“反向无限滚动”非常有帮助。
    • 如果您使用的是ajax,请在ajax success 属性上添加$(selector).scrollTop(firstMsg.offset().top-curOffset); 以使滚动正常工作
    • 太棒了!谢谢杰夫!
    • 有些人来这里可能只是想点击一个按钮而不让按钮四处移动。为此,使用firstMsg.offset() 的计算可以插入使用点击事件的目标元素,使这个sn-p 更便携:var curOffset = $(this).offset().top - $(document).scrollTop(); /* do stuff above the button */ $(document).scrollTop($(this).offset().top-curOffset); c.f. jsfiddle.net/bwz8uLvt/1>(在演示上方,但按钮位于页面中的任意位置)
    • 您的第二个解决方案真的很棒!谢谢,我仍在努力理解为什么它会这样工作。
    【解决方案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;
    

    演示

    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;
    

    【讨论】:

      【解决方案3】:

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

      【讨论】:

        【解决方案4】:

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

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

        【讨论】:

          【解决方案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);
          

          【讨论】:

            【解决方案6】:

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

            // divWithTheScroll.prependElement...
            divWithTheScroll.scrollTop += newlyPrependedElement.scrollHeight;
            

            【讨论】:

              猜你喜欢
              • 2015-12-06
              • 2020-04-06
              • 2015-05-01
              • 1970-01-01
              • 2020-12-20
              • 1970-01-01
              • 2014-08-30
              • 1970-01-01
              • 2019-01-23
              相关资源
              最近更新 更多