问题 Backbone Routers:等待首先获取数据


我认为我不太了解正确使用Backbone路由器背后的想法。这是我得到的:

我有一些数据,我在页面加载时从服务器获取数据,然后将其打包到模型和集合中。这些模型和集合的数量是无限的。我想使用路由器能够直接从一开始渲染某个集合的视图。

问题是:Backbone路由器提前启动,因为我要求它访问某个视图并触发它 render 动作,它不能这样做,因为那些视图尚未创建。这意味着我实际上必须在获取完成后启动我的路由。

我不知道这是否是一种正确的方法,但我想出的唯一想法是:

  1. 包裹路线定义和 Backbone.history.start(); 咬入一个单独的顶级可访问功能(即准备稍后手动调用它)。
  2. 运行该功能作为 success 回调我的收藏品 fetch()
  3. 这些集合的数量是未知的,我也无法找出所有这些集合何时被提取,并且我不想多次启动这些路由。所以我利用了 _.defer() 和 _.once()

这很有效,但看起来很奇怪:

路由器:

    window.startRoutes = _.once(function() {

        var AccountPage = Backbone.Router.extend({

          routes: {
            'set/:id': 'renderSet',
          },

          renderSet: function(setId) {

              /** … **/

              // Call the rendering method on the respective CardView
              CardsViews[setId].render();

          }

        });

        var AccountPageRouter = new AccountPage;

        Backbone.history.start();

    });

采集:

window.CardsCollection = Backbone.Collection.extend({

    model: Card,

    initialize: function(params) {

        /** … **/

        // Get the initial data
        this.fetch({success: function() {
            _.defer(startRoutes);
        }});

    },

});

所以我的问题是......我做得对吗?或者有更好的方法(必须)吗?


5280
2017-10-19 14:06


起源

为什么要立即拨打ajax电话?为什么不简单地使用初始数据加载所需的json渲染页面并将数据传递到骨干启动? - redsquare


答案:


您可以提前定义路由器;在调用Backbone.History.start()之前,它不会做任何事情。

您可以绑定集合上的“重置”事件以启动历史记录,如下所示:

my_collection.bind("reset", _.once(Backbone.History.start, Backbone.History))

然后路由器将在您的集合完全加载时开始执行操作。我不确定这是否正是您正在寻找的(因为您提到了可变数量的集合)。

我有类似的情况,除了我事先知道在开始路由之前我想要加载哪些集合。我在我的路由器上添加了一个startAfter方法,如下所示:

  window.Workspace = new (Backbone.Router.extend({
    . . .
    startAfter: function(collections) {
      // Start history when required collections are loaded
      var start = _.after(collections.length, _.once(function(){
        Backbone.history.start()
      }))
      _.each(collections, function(collection) {
        collection.bind('reset', start, Backbone.history)
      });
    }
  }));

然后在我设置我的收藏品之后

  Workspace.startAfter([collection_a, collection_b, ...])

这可以适用于独立模型,虽然我认为你需要绑定到'重置'事件以外的东西。

我很高兴我阅读了你的示例代码,使用_.once和_.defer指出了我正确的方向。


14
2017-10-19 14:37



不是吗 my_collection.bind("reset", _.once(Backbone.history.start))? - iblue
你使用了错误的论据 _.once()。我会编辑你的答案来解决这个问题。 kthxbye :) - iblue
该 _.once() 例子对我不起作用。我不得不使用: app.users.on("reset", _.once(function () { Backbone.history.start(); })); - Matt Sharpe


我只是在检查我的 .render() 在使用之前填写所有必填字段的方法。如果它还没有填满 - 我正在渲染'载入中...'小部件。

我的所有观点都订阅了模型更改 this.model.bind('change', this.render, this);,所以刚装载模型后, render() 将再次被召唤。


1