如何在反应性呈现新帖子时保持滚动位置

How to maintain scroll position when new posts are reactively rendered?

本文关键字:位置 滚动 新帖      更新时间:2023-09-26

假设我正在渲染一堆帖子。

{{#each posts}}
  {{>post}}
{{/each}}

我收到了一堆按日期排序的帖子。

Posts.find({}, {sort:{name: 1, date:-1}, limit: Session.get('limit')}).fetch()

正如您对移动应用程序所期望的那样,我在这里进行了一些反应性滚动。但现在的问题是,当有人发布新内容时,一切都会下降。我的滚动位置保持不变,但我不再查看同一帖子。

任何想法如何让它工作?

编辑:

在我看来,最优雅的解决方案是颠覆我们对滚动的看法。如果我们以另一种方式对帖子进行排序 - 最旧的在顶部,那么新帖子最终会位于底部,并且不会弄乱scrollTop位置。

编辑2:

我忘了提 - 我不知道我插入的元素的高度。否则我可以满足于丑陋的蛮力方法。

好的,我一直遇到同样的问题,这是我提出的粗略解决方案。告诉我,如果你发现它有什么洞。

Template.postsList.rendered = function (){
this.find('.wrapper')._uihooks = {
    insertElement: function (node, next){
        //hide newly added element, add a class to identify it as a post inserted 
        //after initial load.
        $(node).hide().insertBefore(next).addClass('insertedAfterLoad');
        //if it's at the top of the page, fade it in, otherwise it will stay hidden
        if (getDistance() === 0){
            $(node).fadeIn();
        } 
    }
},
//Continually watch the page while scrolling
$(document).scroll(function(){
        var scrollDistance = getDistance();
        //if any posts have the  'insertedAfterLoad' class, fade them into view.
        //this will only load new posts if the user scrolls back to the top
        if( scrollDistance === 0 && $('.post').hasClass('insertedAfterLoad') ){
            $('.insertedAfterLoad').fadeIn();
        }
});
//This will get the distance to the top of the page of any elements 
//inserted after the initial page load
var getDistance = function(){
        if( $('.post').hasClass('insertedAfterLoad') ){
            return $('.insertedAfterLoad').offset().top;
        }
    }
}

我对你真正想做的事情有点困惑,但如果你想在底部有新帖子并滚动到它们,你可以做一些类似于我在这个应用程序中做的事情使用 scrollTo for Meteor。

首先,将滚动到包添加到流星应用程序中

$ meteor add natestrauser:jquery-scrollto

在用于将表单中的帖子提交到集合的模板事件中,添加带有scrollTo的 setTimeout 函数,该函数将在新帖子添加到集合后触发几毫秒,并将滚动到新帖子:

Template.posts.events({
    "submit .new-post": function (event) {
    var title = event.target.postTitle.value;
    var text  = event.target.postText.value;
    Posts.insert({
      title: title, 
      text: text, 
      date: new Date() // current time
    });
    setTimeout(function(){
        $(".posts-wrapper").scrollTo("max", 500); // change 500 miliseconds to whatever speed you want
    }, 100);
    // Clear form
    event.target.postTitle.value = "";
    event.target.postText.value = "";
    // Prevent default form submit
    return false;
  }
});

模板助手,我们在其中获取帖子、进行排序等:

Template.posts.helpers({
    posts: function() {
        return Posts.find({}).fetch;
    }
}); 

带有表单的模板,用于添加帖子以及那些使用类.posts-wrapper div呈现的帖子:

<template name="posts">
    <form class="new-post">
        <label>Post title: </label>
        <input type="text" name="postTitle">
        <label>Post text: </label>
        <input type="textarea" name="postText">
    </form>
    <div class="posts-wrapper">
        {{#each posts}}
            {{> post}}
        {{/each}}
    </div>
</template>

你可以在这里看到它的实际效果,并检查这个Meteorpad中的代码。

如果您需要滚动整个<body>,只需使用:

setTimeout(function(){
    $("body").scrollTo("max", 500); // change 500 miliseconds to whatever speed you want
}, 100);