【问题标题】:infinite scroll with ember.js (lazy loading)ember.js 无限滚动(延迟加载)
【发布时间】:2012-08-08 01:49:42
【问题描述】:

我有一个视图,其中可以有大量项目供用户滚动浏览,我想实现无限滚动以实现内容的渐进式加载。

看起来有些人 have done pagination 但 Google 并没有提出任何人讨论他们如何使用 Ember/Ember Data 完成无限列表。有人已经解决了这个问题并有一篇博文/示例代码可以分享吗?

【问题讨论】:

  • 非常好的问题,我希望你能得到答案,因为在这里我完全不知道该怎么做,我很确定我会需要它。
  • 无限滚动的概念看起来很简单,你只是对数据进行分页,而不是从 UI 中删除现有内容并用你从商店带来的任何内容替换它(通常是表格数据视图) ,你会将它附加到容器中(比如 ul 和几个 li 附加到它的元素),但可能还涉及其他一些东西(比如缓存和类似的东西)。我想看一个例子,因为我现在没有时间开始尝试编码
  • 对这个问题也很感兴趣——尤其是关于存储中应该有多少数据但尚未显示(@MilkyWayJoe 提到的缓存)。在相关的说明中,如果最重要的结果发生了变化(例如推文已被推文),如何最好地处理分页的变化?
  • 如果触及“无限滚动”的事件发生在服务器端 - 正如你提到的新推文已添加 - 应用程序应使用这些始终连接的框架之一(例如 node.js、signalr .js) 在客户端触发某些东西以加载更多结果。此外,客户端必须有一些东西来监视页面的滚动 - 显然 - 才能触发使用来自服务器的数据的函数。

标签: ember.js lazy-loading infinite-scroll ember-data


【解决方案1】:

我建议使用Ember Infinity 插件。 它支持 Ember 1.10 到 2.0+。 设置起来相对容易。您只需要修改您的路线和模板。

路线(Product 是示例模型):

import InfinityRoute from 'ember-infinity/mixins/route';

export default Ember.Route.extend(InfinityRoute, {
  model() {
    /* Load pages of the Product Model, starting from page 1, in groups of 12. */
    return this.infinityModel('product', { perPage: 12, startingPage: 1 });
  }
});

模板:

{{#each model as |product|}}
  ...
{{/each}}

{{infinity-loader infinityModel=model}}

{{infinity-loader}} 组件变得可见时,它会向您的路由发送一个操作,因此它知道用新的(获取的)记录来更新模型数组。

第一个请求将被发送到:

/products?per_page=12&page=1

因此,您还需要准备后端 API 来处理这些查询参数。显然是可定制的,看看Advanced Usage section of Readme

注意

使用 ListView(@commadelimited 的回答)和使用 ArrayController(@pangratz 的回答)的视图都已弃用/删除,因为 Ember 2.0 是稳定版本。

【讨论】:

    【解决方案2】:

    我正在根据@pangratz 的工作编写infinite pagination plugin for Ember

    如果您有任何问题或需要改进,请在此处提出任何问题。

    【讨论】:

    【解决方案3】:

    你知道新发布的 Ember.ListView 组件吗?

    https://github.com/emberjs/list-view

    它是在 2 月的旧金山 Ember 聚会上宣布的。下面是来自 Ember Core 开发人员之一的 Erik Bryn 关于使用它的幻灯片:

    http://talks.erikbryn.com/ember-list-view/

    【讨论】:

    • 这可以与 ember-data 和顺序页面查询一起使用吗?
    • 可以 def 与 Ember.Data 一起使用。我相信它会为你分页。查看上面的第二个链接,因为它有一个 Erik Bryn 所做的演示视频。
    • 控件知道对其基础内容的更新,如果它发生更改,列表将更新。似乎没有无限滚动行为。
    • 据我所知,有一些问题需要使用该控件进行排序。首先,它是带有自己的滚动条的自己的框架——不适合任何类似引导程序的东西。其次,ember-data 不会提供可变数据集,因此在连接所有内容时需要更多的参与。
    【解决方案4】:

    我已经在GitHub Dashboard project 实现了无限滚动机制,我目前正在开发中。该功能在提交68d1728 中添加。

    基本思想是有一个LoadMoreView,每当视图在当前视口上可见时,它就会在控制器上调用loadMore 方法。我为此使用了 jQuery 插件 inview。它允许您注册inview 事件,当指定选择器的元素在屏幕上可见和消失时触发。

    控制器还具有指示是否有更多要加载的项目以及当前是否已获取项目的属性。这些属性称为canLoadMoreisLoading

    LoadMoreView 基本上是这样的:

    App.LoadMoreView = Ember.View.extend({
      templateName: 'loadMore',
      didInsertElement: function() {
        var view = this;
        this.$().bind('inview', function(event, isInView, visiblePartX, visiblePartY) {
          if (isInView) Ember.tryInvoke(view.get('controller'), 'loadMore');
        });
      }
    });
    

    其中loadMore模板定义如下:

    {{#if isLoading}}
        fetching some more stuff <img width="10" src="img/ajax-loader.gif" >
    {{else}}
        {{#if canLoadMore}}
            <a {{action "loadMore" target="controller" }}>click to load more items</a>
        {{else}}
            <i>no more items</i>
        {{/if}}
    {{/if}}
    

    处理获取更多项目的控制器然后实现如下。请注意,在 loadMore 方法中,会执行对商店的查询,该查询会加载模型条目的特定页面。

    App.EventsController = Ember.ArrayController.extend({
      currentPage: 1,
    
      canLoadMore: function() {
        // can we load more entries? In this example only 10 pages are possible to fetch ...
        return this.get('currentPage') < 10;
      }.property('currentPage'),
    
      loadMore: function() {
        if (this.get('canLoadMore')) {
          this.set('isLoading', true);
          var page = this.incrementProperty('currentPage');
    
          // findQuery triggers somehing like /events?page=6 and this
          // will load more models of type App.Event into the store
          this.get('store').findQuery(App.Event, { page: page });
        } else {
          this.set('isLoading', false);
        }
      }
    });
    

    剩下的唯一事情是最初将控制器的content 设置为filter 函数的结果,因此content 会在新模型加载到商店时更新(这是由于@ 987654341@ 方法在控制器的loadMore 中)。此外,在调用 filter 时会添加 query 哈希。这可确保对服务器进行初始查询。

    App.eventsController = App.EventsController.create({
        content: []
    });
    
    var events = App.store.filter(App.Event, { page: 1 }, function(data) {
        // show all events; return false if a specific model - for example a specific
        // type of event - shall not be included
        return true;
    });
    

    【讨论】:

    • 非常有帮助,但你为什么要使用过滤器?您实际上并没有过滤任何东西(即return true),那么使用过滤器还有其他好处吗?
    • 你为什么使用Ember.tryInvoke
    • 我真的没有走到最后一步,var event = ...。为什么将其保存在变量中?变量用在哪里,过滤器有什么用?
    • 惊人的答案。谢谢!!我已经根据您的工作制作了一个版本,以防它对其他人有帮助。 github.com/iHiD/meducation_mobile_app/commit/….
    • 可以包含 Ember.ViewTargetActionSupport mixin 并使用 view.triggerAction {action: 'loadMore'} 来从控制器触发动作,而不是 Ember.tryInvoke。在这里检查你:emberjs.com/api/classes/Ember.ViewTargetActionSupport.html
    猜你喜欢
    • 2011-01-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-09-12
    • 2017-08-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多