【问题标题】:Structuring my backbone.js application构建我的backbone.js 应用程序
【发布时间】:2011-11-07 21:53:24
【问题描述】:

我正在使用 Require.js 创建一个 Backbone.js 应用程序。每个视图文件对应一个资源(例如“新闻”)。在每个视图文件中,我声明了一个主干 查看每个操作(“索引”、“新”等)。在我收到的视图文件的底部 来自路由器的必要信息,然后决定实例化哪个视图(基于从路由器传入的信息)。

这一切都很好,但它需要大量代码并且似乎不是“backbone.js 方式”。一方面,我依靠 url 来管理状态。另一方面,我没有使用 _.bind ,它出现在很多backbone.js 示例中。换句话说,我认为我做的不对,而且我的代码库有异味……关于如何更好地构建我的应用程序有什么想法吗?

路由器.js

define([
  'jquery',
  'underscore',
  'backbone',
  'views/news'], 
  function($, _, Backbone,  newsView){
    var AppRouter = Backbone.Router.extend({
        routes:{
            'news':'news',
            'news/:action':'news',
            'news/:action/:id':'news'
        },

        news: function(action, id){
            newsView(this, action, id).render();
        }
    });


    var intialize = function(){
        new AppRouter;
        Backbone.history.start()
    };

    return{
        initialize: initialize;
    };
}

news.js ('views/news')

define([
  'jquery',
  'underscore',
  'backbone',
  'collections/news',
  'text!templates/news/index.html',
  'text!templates/news/form.html'

  ], function($, _, Backbone, newsCollection, newsIndexTemplate, newsFormTemplate){

    var indexNewsView = Backbone.View.extend({
        el: $("#content"),

        initialize: function(router){
            ...
        },

        render: function(){
            ...
        }
    });

    var newNewsView = Backbone.View.extend({
        el: $("#modal"),

        render: function(){
            ...
        }
    });

    ...

    /*
     *  SUB ROUTER ACTIONS
     */

    var defaultAction = function(router){
      return new newsIndexView(router);
    }

    var subRouter = {
      undefined: function(router){return defaultAction(router);},

      'index': function(router){ return defaultAction(router);},

      'new': function(){
        return new newNewsView()
      },

      'create': function(router){
        unsavedModel = {
          title : $(".modal-body form input[name=title]").val(),
          body  : $(".modal-body form textarea").val()
        };
        return new createNewsView(router, unsavedModel);
      },

      'edit': function(router, id){
        return new editNewsView(router, id);
      },

      'update': function(router, id){
        unsavedModel = {
          title : $(".modal-body form input[name=title]").val(),
          body  : $(".modal-body form textarea").val()
        };

        return new updateNewsView(router, id, unsavedModel);
      },
    }

    return function(router, action, id){
      var re = /^(index)$|^(edit)$|^(update)$|^(new)$|^(create)$/
      if(action != undefined && !re.test(action)){
        router.navigate('/news',true);
      }
      return subRouter[action](router, id);
    }


  });

【问题讨论】:

    标签: backbone.js requirejs


    【解决方案1】:

    虽然我觉得强调没有真正的“Backbone.js 方式”很重要,但您似乎在复制 Backbone 应该为您做的工作。

    我同意为应用程序的每个独立部分使用专门的路由器是有意义的。但乍一看,您在“子路由器”部分所做的只是重新创建Backbone.Router 功能。您的AppRouter 根本不需要处理/news URL;您可以使用特定于新闻的路由初始化 NewsRouter,它将处理与新闻相关的 URL:

    var NewsRouter = Backbone.Router.extend({
        routes:{
            'news':             'index',
            'news/create':      'create',
            'news/update/:id':  'update',
            'news/edit/:id':    'edit'
        },
    
        index: function() { ... },
    
        create: function() { ... },
    
        // etc
    });
    

    只要在您调用Backbone.history.start() 之前对其进行初始化,它就会捕获其路由的URL 请求,而您永远不必处理AppRouter。您也不需要处理视图底部的丑陋代码 - 这基本上只是在做核心 Backbone.Router 为您所做的事情。

    【讨论】:

    • 如果您希望您的应用程序更加模块化并且对于每个模块您不希望他们必须了解其他模块怎么办?对于小型应用程序来说,所有东西都在一个路由器上可以工作,但随着事情的发展,让模块能够解析自己的路由会很有帮助!并不是说上面的实现是完美的,只是说它可以(并且对我们来说)有用。遗憾的是您无法在 Backbone.history.start() 之后修改路由器 :)
    • 可以使用router.route动态添加路由:http://documentcloud.github.com/backbone/#Router-route
    • @nrabinowitz 在您看来更好的是每个动作都有一条路线,还是有一条资源路线,并使用事件来处理动作?
    • @LDK - 这取决于您的应用程序。通常我每个动作都有一条路线 if 每个动作都需要不同的视图,例如/resource/edit 需要一个编辑器视图。主要问题是,您是否希望用户能够为路线添加书签或使用后退按钮?
    • @nrabinowitz 极好的点:路线和书签。模态视图呢?大部分视图保持不变,除了出现一个模式。我想这取决于我是否希望用户在后台看到以前的视图。
    【解决方案2】:

    我也在使用 require.js 和主干,我认为我建议的主要区别是每个文件应该只返回一个视图、模型、路由器或集合。

    所以我的主 html 页面需要我的主路由器。该路由器是一个模块,它需要基于每个路由的一些视图和一个引导模型。每个路由器方法将相关的引导模型片段传递给相关视图。

    从那里开始,只要每个文件只是 1 个主干事物(模型、集合、视图、路由器)并且只需要它使用的元素,它就会保持非常干净。这会产生很多 js 文件(我目前的项目大约有 100 个),但这就是 require.js 优化发挥作用的地方。

    希望对你有帮助。

    【讨论】:

    • 总的来说我喜欢这种方法,但我担心你必须通过 require.js 传入许多模块。例如,路由器模块不需要很多视图模块吗?
    • 可能,但是如果您开始在一台路由器中获得 5,6,7 条路由,您应该开始考虑将它们拆分。所以你会有一个 main.js,它需要 router1、router2、router3,创建所有 3 个并启动历史记录。然后你又在逻辑上把事情分开了。
    【解决方案3】:

    你为什么不这样安排你的路线:

            routes:{
                'news':'news',
                'news/edit/:id':'editNews',
                'news/new':'newNews',
                ...
            }
    

    【讨论】:

    • 这样做会创建很多功能。如果一个应用程序有 4 个资源,每个资源有 7 个操作,那么需要在路由文件中定义 28 个函数。我也不热衷于为每个资源重新输入所有内容。
    • 比写一个函数,它需要一些资源并返回每个资源的路由。此外,无论如何都必须编写函数,甚至在示例代码中也是如此。它只是将它移动到一个添加了更多样板的子路由器中。顺便说一句,我同意多个路由器上的@nrabinowitz。
    猜你喜欢
    • 1970-01-01
    • 2011-08-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-06-19
    相关资源
    最近更新 更多