Backbone.js:模型,集合,路由器,何时以及为何?

fed*_*sas 4 javascript model-view-controller backbone.js underscore.js

我仍然试图绕过Backbone.js我看了一些截屏并阅读了一些教程.我也是RTFM.但是,我对每个人似乎都在使用框架的某些部分来处理不同的任务感到困惑.

在使用传统的待办事项列表应用程序后,我决定在真实应用程序中首次拍摄backbone.js.

我的应用程序将收到一个充满问题的JSON对象.然后,我喜欢有一个'ul',我可以在那里移动这些问题(下一个q,前一个q).我已经有了一个显示按钮的视图,并在用户点击"下一个"或"上一个"时通知.我的问题是:我应该在哪里处理我的'currentQuestion','next'和'previous'功能的逻辑.我见过一些人使用Collection这个,还有一些人使用Model.这让我很困惑.

任何人都可以指出一些元代码来处理这个问题?非常感谢!

Mat*_*hew 7

这个问题没有真正正确的答案.肯定有不止一种方法可以使它工作,这是关于Backbonejs的一个好处:它非常灵活,并没有对你施加太多的设计选择.

如果我要开始构建你所描述的内容,我肯定会:

  • 一个Question模型
  • 一个Questions集合
  • a QuestionView用于呈现单个问题
  • a QuestionsIndexView用于显示问题列表

在那之后,事情变得有点模糊,这取决于您对应用程序的要求.如果您希望状态像传统网站一样存储,您可以使用路由器并执行类似下面的操作:

 ApplicationRouter = Backbone.Router.extend({

    routes: {
       "": "index",
       "question/:id": "show"
    },

    index: function() {
        // render a QuestionsIndexView...
    },

    show: function(id) {
        // find the q and render a QuestionView...
    }
 })
Run Code Online (Sandbox Code Playgroud)

这很好,因为状态是在URL中维护的,因此用户可以使用浏览器前进和后退按钮,事情可能会像他们期望的那样工作.这个问题是,我们应该如何使这些nextQuestionpreviousQuestion按钮工作?

如果你把它们作为QuestionView一个问题的一部分就必须知道它的下一个和前面的问题是什么.你也许可以想出一个方案,使这项工作,但更优雅和经常使用的方式是创建一个以上的所有我们所提到的已经调用数据模型的存在另一种模式App,然后进行QuestionsCollectioncurrent_question_id此模型的属性.然后我们将current_question_id在路由器方法中更新此attr.

现在我们正在烹饪,我们的应用程序状态不仅存在于浏览器的URL中,而且还作为可观察对象存在于应用程序层.我们可以轻松创建一个ButtonsPanelView传递此App模型并在单击其按钮时触发正确路径的模型.这也是微不足道的实施hasNextQuestion,并hasPreviousQuestionApp模型,并用它来toggle或禁用相应的按钮,当用户不能后退或前进.

按要求编辑:

使一个App存在于其他一切之上的模型非常简单.您可能已经在某处看起来像这样的代码:

window._qs = new Questions();
window._qs.fetch();
Run Code Online (Sandbox Code Playgroud)

只需这样做:

var qs = new Questions();
window.app = new App({questions: qs});
qs.fetch();
Run Code Online (Sandbox Code Playgroud)

现在,Questions集合是应用模型的一个属性,正如我们想要的那样.那么App看起来像是什么样的定义?同样,有很多方法可以解决这个问题,但我喜欢使用Backbone.Models的验证来确保我不会陷入糟糕的状态.这是我可能做的:

App = Backbone.Model.extend({

   defaults: {
      current_question_index: 0
   },

   validate: function(attrs) {

      if(typeof attrs.current_question_index !== "undefined") {
         // we are trying the change the question index,
         // so make sure it is valid
         var len = this.get("questions").length
         if(attrs.current_question_index < 0 || attrs.current_question_index >= len) {
            // returning anything prevents invalid set
            return "index is out of bounds"; 
         }
      }
    },

    hasNextQ: function() {
      var next_ind = this.get("current_question_index") + 1;
      // use the logic we already created, in validate() but
      // convert it to a bool. NOTE in javascript:
      //       !"stuff"   === false
      //       !undefined === true 
      return !this.validate({current_question_index: next_ind}); 
    },

    nextQ: function() {
      var next_ind = this.get("current_question_index") + 1;
      // validate() will prevent us from setting an invalid index
      return this.set("current_question_index", next_ind);

    }

});
Run Code Online (Sandbox Code Playgroud)