最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Lock scroll as new content is added above and below - Stack Overflow

programmeradmin2浏览0评论

I have a meteor.js app that functions as a news feed, with threads being posted and people menting on the threads in realtime. This means that while you are looking at a post, there will be new ments being added to posts above and below and new threads will be added above. This will push the post you are focusing on down and out of the viewport, which is never expected (unless you're already scrolled to the top).

What is the best way to update the scrolling to maintain the same visual center as new content is added?

I have a meteor.js app that functions as a news feed, with threads being posted and people menting on the threads in realtime. This means that while you are looking at a post, there will be new ments being added to posts above and below and new threads will be added above. This will push the post you are focusing on down and out of the viewport, which is never expected (unless you're already scrolled to the top).

What is the best way to update the scrolling to maintain the same visual center as new content is added?

Share Improve this question asked Dec 21, 2015 at 22:07 JacobPariseauJacobPariseau 1951 silver badge13 bronze badges 1
  • i'd suggest you don't update the post ments until you scroll them into view: that way the user actually sees that there has been an update and it's being loaded as s/he goes by it. Otherwise it'd be quite difficult to know which ones are new and which ones are old, and which ones the user may have already read. This is not the answer to your question but I think it would lead to a better user experience. – MrE Commented Jan 6, 2016 at 18:50
Add a ment  | 

3 Answers 3

Reset to default 3 +50

You could try this approach:

  1. save the scrollTop value;
  2. prepend the content (i.e., add a new post above the one that's focused);
  3. add the height of the new content to the value saved in step 1;
  4. scroll to the new value.

Here's an example:

function randomString() {
  return Math.random().toString(36).substring(7);
}

$('#addAbove').on('click', function(e){
  var newDiv = $('<li class="post">' + randomString() + '</li>');
  var savedScrollTop = $('#content').scrollTop();
  $('#content').prepend(newDiv);
  $('#content').scrollTop(savedScrollTop + newDiv.height());
});

$('#addBelow').on('click', function(e){
  var newDiv = $('<li class="post">' + randomString() + '</li>');
  $('#content').append(newDiv);
});
#content {
  height: 100px;
  overflow-y: scroll;
}
.post {
  height: 40px;
}
<script src="https://ajax.googleapis./ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul id="content">
  <li class="post">u9tv190be29</li>
  <li class="post">dgdr8gp66rp</li>
  <li class="post">93vfntdquxr</li>
</ul>
<button id="addAbove">Add Above</button>
<button id="addBelow">Add Below</button>

Appending content below the current viewport shouldn't require adjustment.

Here's a blog post describing a similar approach, and a similar SO question.

I suggest you do like so, when a new item is to be added you check if you are at the top, if so, then just add the new item.

If not, you get the existing top/height of your item container, add the new item, get the item containers height a second time and then update the scroll top.

Here is a simple sample of how one can do, adding at both top and bottom (btw, at bottom don't need scroll pensation).

function addItem (totop) {
  var msgdiv = document.getElementById('items');
  var attop = scrollAtTop(msgdiv);
  var prevtop = parseInt(msgdiv.scrollHeight - msgdiv.scrollTop);

  if (totop) {
    msgdiv.innerHTML = 'Long long content ' + (tempCounter++) + '!<br/>' + msgdiv.innerHTML;

    if (!attop) {
      updateScroll(msgdiv, parseInt(msgdiv.scrollHeight) - prevtop);
    }
  } else {
    msgdiv.innerHTML += 'Long long content ' + (tempCounter++) + '!<br/>';
  }
}

var tempCounter = 10;
function updateScroll(el, top){
  el.scrollTop = top;
}
function scrollAtTop(el){
  return (el.scrollTop == 0);
}
html, body { height:100%; margin:0; padding:0; }

.items{
  display: inline-block;
  width: 300px;
  height: 220px;
  border: 1px solid black;
  overflow: auto;
}


button { width: 15%; height: 44px; margin: 20px; vertical-align: top; }
<div class="items" id="items">
  Long long content 9!<br/>
  Long long content 8!<br/>
  Long long content 7!<br/>
  Long long content 6!<br/>
  Long long content 5!<br/>
  Long long content 4!<br/>
  Long long content 3!<br/>
  Long long content 2!<br/>
  Long long content 1!<br/>
</div>
<button onclick="addItem(true);">Add 2 top</button><button onclick="addItem(false);">Add 2 bottom</button>

You can use package animated-each meteor add mizzao:animated-each, to solve the problem.

It would be certainly better than implementing custom jquery. And if package does not solve exact problem, then you can use it as an example on how to hook into rendering and create solution the meteor way. Probably by utilising meteor-ui-hooks

发布评论

评论列表(0)

  1. 暂无评论