【问题标题】:Large backbone.js web app organization大型backbone.js Web 应用程序组织
【发布时间】:2011-12-21 14:47:11
【问题描述】:

我目前正在开发一个基于backbone.js 的大型网络应用程序,并且在组织、“僵尸”等方面遇到了很多问题,因此我决定对代码进行重大重构。我已经写了一堆处理“僵尸”的辅助函数;但是,我想从一开始就为代码创建一个很好的结构/组织。我没有找到很多关于大型骨干网.js 组织的优秀教程/示例,所以我有点从头开始,想看看我是否可以就我从哪里开始获得一些意见。

我显然已经在全局命名空间中设置了我的代码;但我也想保持该命名空间相当干净。我的主 app.js 将类文件本身与全局命名空间分开;您可以使用 reg() 函数注册一个类(以便实例化),而 inst() 函数从 classes 数组中实例化一个类。因此,MyApp 命名空间除了这 3 个方法外,只有 Router、Model 和 View:

var MyApp = (function () {

    var classes = {
        Routers: {},
        Collections: {},
        Models: {},
        Views: {}
    };

    methods = {

        init: function () {
            MyApp.Router = MyApp.inst('Routers', 'App');
            MyApp.Model = MyApp.inst('Models', 'App');
            MyApp.View = MyApp.inst('Views', 'App');
            Backbone.history.start();
        },

        reg: function (type, name, C) {
            classes[type][name] = C;
        },

        inst: function (type, C, attrs) {
            return new classes[type][C](attrs || {});
        }

    };

    return methods;

}());

$(MyApp.init);

在模型、集合、路由器和视图中,我照常工作,但需要在文件末尾注册该类,以便稍后实例化(不会弄乱命名空间):

MyApp.reg('Models', 'App', Model);

这似乎是一种不必要的代码组织方式吗?其他人是否有更好的示例来说明如何组织具有许多路由器、集合、模型和视图的大型项目?

【问题讨论】:

标签: javascript jquery namespaces backbone.js organization


【解决方案1】:

这 2 个资源帮助我在坚固的地下室设置了我的主干应用程序:

【讨论】:

    【解决方案2】:

    其实不同的方式各有优缺点。最重要的是找到合适的文件组织方式。以下是我目前正在做的项目的组织方式。这种方式的焦点将相同的模块相关文件放置在一个文件夹中。例如:people模块,这个模块的所有文件都放在modules/base/people目录下。本模块更新维护后,只需要关注本目录下的文件就行,不会影响目录外的文件,提高了可维护性。

    希望我的回答能给你一些帮助,也希望你提点宝贵意见。

    【讨论】:

    • 我也有一个包含模块的文件夹,但我认为每个模块文件夹至少需要模型文件夹和视图文件夹
    • context.js 有什么用?你有github吗?
    【解决方案3】:

    我的命名空间类似于你正在做的事情(至少对于类部分),我所有的模型、视图和控制器看起来像这样:

    views/blocks.js:

    (function(cn){
        cn.classes.views.blocks = cn.classes.views.base.extend({
    
            events: {},
    
            blocksTemplate: cn.helpers.loadTemplate('tmpl_page_blocks'),
    
            initialize: function(){
            },
    
            render: function(){
                $(this.el).html(this.blocksTemplate());
            },
    
            registerEvents: function(){},
            unregisterEvents: function(){}
        });
    })(companyname);
    

    我的 JavaScript 命名空间看起来像这样,尽管我每次构建新应用时都会对其进行改进:

     companyname:{                                                                                                                                                                                 
       $: function(){},      <== Shortcut reference to document.getElementById                                                                                                                      
       appView: {},          <== Reference to instantiated AppView class.                                                                                                                           
       classes = {           <== Namespace for all custom Backbone classes.                                                                                                                         
         views : {},                                                                                                                                                                                
         models : {},                                                                                                                                                                               
         collections: {},                                                                                                                                                                           
         controllers : {},                                                                                                                                                                          
         Router: null                                                                                                                                                                               
       },                                                                                                                                                                                           
       models: {},          <== Instantiated models.                                                                                                                                                
       controllers: {},     <== Instantiated controllers.                                                                                                                                           
       router: {},          <== Instantiated routers.                                                                                                                                               
       helpers: {},         <== Reusable helper platform methods.                                                                                                                                   
       currentView: {},     <== A reference to the current view so that we can destroy it.                                                                                                          
       init: function(){}   <== Bootstrap code, starts the app.                                                                                                                           
     } 
    

    我希望我的所有视图都具有任何内容,我将其放入基本视图中。我的控制器将在它创建的任何新视图(渲染后)上调用registerEvents,并在它杀死它之前在视图上调用unregisterEvents。并非所有视图都有这两个额外的方法,因此它首先检查是否存在。

    不要忘记所有视图都带有内置的this.el.remove();。这不仅会杀死视图容器元素,还会解除绑定到它的所有事件。根据您通过控制器创建视图的方式,您可能实际上并不想杀死元素并执行 this.el.unbind() 而是取消绑定所有事件。

    【讨论】:

    • 在什么情况下我不想杀死元素并执行 this.el.unbind()?我有一个方法 close 可以执行以下操作: if (this.onClose) this.onClose(); $(this.el).remove(); $(this.el).unbind();
    • .remove 自动执行.unbind,所以你应该很好。
    【解决方案4】:

    我最近参与了一个名为 GapVis (code here, rendered content here) 的 Backbone 项目。我不知道它是否“真的很大”,但它很大而且相对复杂——24 个视图类、5 个路由器等。可能值得一看,尽管我不知道我所有的方法都是相关的。您可以在我的main app.js file 的长介绍评论中看到我的一些想法。几个关键的架构选择:

    • 我有一个单独的 State 模型,它包含所有当前状态信息 - 当前视图、我们正在查看的模型 ID 等。每个需要修改应用程序状态的视图都通过设置属性来实现State,每个需要响应状态的视图都会监听该模型的事件。对于修改状态和更新的视图来说也是如此——events 中的 UI 事件处理程序从不重新渲染视图,而是通过将渲染函数绑定到状态来完成。这种模式确实有助于保持视图彼此分离 - 视图永远不会在另一个视图上调用方法。

    • 我的路由器被视为专用视图 - 它们通过更新状态来响应 UI 事件(即输入 URL),并通过更新 UI(即更改 URL)来响应状态变化。

    • 我做了几件类似于你提议的事情。我的命名空间有一个类似于您的 init 函数,以及一个用于常量的 settings 对象。但我也将大部分模型和视图类放在命名空间中,因为我需要在多个文件中引用它们。

    • 我为我的路由器使用了一个注册系统,并为我的观点考虑了一个注册系统,这是一种让“主”类(AppRouterAppView)不必了解每个视图的好方法.不过,在AppView 的情况下,事实证明子视图的顺序很重要,所以我最终对这些类进行了硬编码。

    我很难说这是做事的“正确”方式,但它对我有用。我希望这会有所帮助 - 我也很难找到使用 Backbone 的大型项目的可见源示例,并且在我进行过程中必须解决大部分问题。

    【讨论】:

    • 感谢您提供的所有信息;我很高兴我们都有相似的思维过程——这至少证明了我没有疯哈哈。我绝对喜欢您关于更频繁地使用事件并将路由器用作简单的“url 视图”的想法。我想我仍然不太确定我的所有类的注册系统是否值得......它不会弄乱全局命名空间,但这有关系吗?将 MyApp 命名空间与类文件混淆是否存在性能问题?
    • 如果您的主要目标是保持命名空间清洁,我认为您可能想多了这部分 - 我不知道有任何性能问题,问题更多是关于代码组织。使用 var MyClass 而不是 ns.MyClass 有一些压缩优势,这通常不能被修改,但它是最小的,而且你仍然使用字符串名称。
    猜你喜欢
    • 1970-01-01
    • 2015-01-20
    • 2010-10-05
    • 1970-01-01
    • 2016-11-15
    • 1970-01-01
    • 2014-05-16
    • 2010-11-18
    • 1970-01-01
    相关资源
    最近更新 更多