12

我有一大组数据,我想将它们拆分为通过 Meteor 中的无限滚动加载的部分,以防止一次加载大型数据集;相反,我会在需要时加载数据集的块。如何在保留无限滚动加载的每个部分的实时页面更新的同时这样做?

4

4 回答 4

8

这是我用于电影数据库游乐场的代码。我尝试了jQuery事件,但最终决定如果数据连续传输就足够了。我的测试集合是 680 条记录,有 20 个字段和一个缩略图字段,每个封面在 10-20kb 之间。这里是 Coffeescript 代码:

Movies = new Meteor.Collection("movies")
if Meteor.isClient
  # starting with 10 items that the user sees a page fast
  Session.set("queryLimit", 10)

  # getting the item count from the server collection
  Meteor.call 'getMoviesCount', (err, result) =>
    Session.set('itemsInQuery',result)
  # subscribe to a subset of the collection, and change the Session var on completion
  # automatically changing the limit of the publishing function with autorun
  Meteor.autorun ->
    Meteor.subscribe "MoviesList", Session.get("queryLimit"),  onComplete = ->
      if Session.get("queryLimit") < Session.get('itemsInQuery')
        queryLimit = Session.get("queryLimit") + 30 #change iterator depending on result size 
        Session.set("queryLimit", queryLimit )

  # Client helper to add more items to handlebars template
  Template.app.helpers movies: ->
    Movies.find({})

if Meteor.isServer
  Meteor.publish "MoviesList", (limit) ->
    # show whole collections once limit is reached, by setting limit to 0
    limit = 0 if limit > Movies.find().count() 
    console.log new Date(), limit
    Movies.find({}, { limit: limit, fields: {title:1 } } ) #use fields to test different result sizes  

  Meteor.methods
    getMoviesCount: (query) ->
      return Movies.find().count()

和html:

<body>
  {{> app}}
</body>
<template name="app">
    {{#each movies}}
      <p>{{title}}</p>
    {{/each}}
</template>

我做了一些快速的性能测试,结果发现对于每条记录的几行文本,向客户端发送数据的最快方式是限制在 100 左右。我也尝试使用嵌入在文件中的 10-20kb 缩略图. 当使用更大的资产时,当限制大于 30 条记录时,Chrome 变得非常无响应。这里有一些在 localhost 上完成的统计数据(每个运行 3 次):

limit   seconds till last record rendered.
  0     79s 
  010   121s
  020   64s  
  030   45s
  050   34s
  100   16s
  200   16s

有趣的是,流星服务器一次发送整个页面大约需要 79 秒(limit=0)。我不确定这怎么可能,因为连续流应该是最快的。所以我的统计数据可能有些有趣。有任何想法吗?

于 2013-02-15T22:48:30.747 回答
3

我的解决方案类似于 Andrej 的解决方案。因为我在数据库中有很多记录,我不希望我的服务器一次发送它们,所以在服务器上我得到了:

Meteor.publish("items", function(page) {
    if(!page)
        page = 1;
    var limit = 30 * page;
    return Items.find({}, {limit: limit};
}

客户:

Template.templateName.items = function () {
    Meteor.subscribe("items", Session.get("page"));
    return Items.find({});
}

还有一个 jQuery 函数来观察页面是否到达底部:

$(window).scroll(function(){
    if ($(window).scrollTop() == $(document).height()-$(window).height()){
        Session.set("page", Session.get("page") + 1);
    }
});

还要在模板创建的回调上设置页面初始页面:

Template.templateName.created = function() {
    Session.setDefault("page", 1);
};

在模板中,我使用 {{#each}} 显示这些项目另外,我必须检查是否没有更多记录

更好的解决方案是在创建模板时显示 30,然后在滚动时再显示 30,但我不知道如何显示它们。我可能有一个解决方案,但我懒得实施,因为我不确定它是否会起作用。我正在考虑附加呈现的html

于 2013-09-04T13:56:26.803 回答
1

您可以设置一个会话密钥来存储您当前所在的页面。就像是:

Session.set("cur_page", 1);

然后你将它输入到你的查询中,例如:

Template.list.items = function() {
  return Collection.find({}, {
    skip: Session.get("cur_page") * page_size,
    limit: page_size
  });
}

然后您只需更新值,Session.set("cur_page", 2)您的列表将重新绘制第 2 页的项目。Tadaa!

于 2013-01-05T01:33:24.083 回答
1

我还没有尝试过,但它应该可以工作。所以,如果你有你的收藏:

var Posts = new Meteor.Collection("posts");

还有你的模板:

<template name="posts">
    {{#each posts}}
        {{> post}}
    {{/each}}
</template>

这可能是您的模板助手:

Template.posts.helpers({
    posts: function() {
        return Posts.find({}, {limit: Session.get("current_page")*PAGE_SIZE});
    }
});

其中 PAGE_SIZE 是每个“页面”的帖子数量。每次用户滚动到页面底部时,您都需要增加“current_page”会话变量。然后模板将更新,您的无限滚动(希望)有效!

于 2013-02-17T14:24:08.100 回答