Javascript 大型backbone.js Web 应用程序组织
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/8002828/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Large backbone.js web app organization
提问by user527480
I'm currently working on a large web app built on backbone.js and have been having a lot of issues with organization, "zombies," etc. so I've decided to do a major refactor of code. I've already written a bunch of helper functions for dealing with the "zombies"; however, I'd like to start from the very beginning and create a nice structure/organization to the code. I haven't found many great tutorials/examples on large-scale backbone.js organization so I've sort of started from scratch and would like to see if I can get some opinions on where I've begun.
我目前正在开发一个基于 Backbone.js 的大型 Web 应用程序,并且在组织、“僵尸”等方面遇到了很多问题。所以我决定对代码进行重大重构。我已经写了一堆处理“僵尸”的辅助函数;但是,我想从头开始并为代码创建一个很好的结构/组织。我还没有找到很多关于大型backbone.js 组织的很棒的教程/示例,所以我从头开始,想看看我是否可以就我的起点获得一些意见。
I've obviously set up my code within a global namespace; but I'd also like to keep that namespace rather clean. My main app.js keeps the class files themselves separate from the global namespace; you can register a class (so that it can be instantiated) by using the reg() function and the inst() function instantiates a class from the classes array. Thus, besides the 3 methods, the MyApp namespace only has Router, Model and View:
我显然已经在全局命名空间中设置了我的代码;但我也想保持该命名空间相当干净。我的主要 app.js 将类文件本身与全局命名空间分开;您可以使用 reg() 函数注册一个类(以便它可以被实例化),而 inst() 函数从类数组中实例化一个类。因此,除了 3 个方法之外,MyApp 命名空间只有 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);
Within the Models, Collections, Routers and Views, I work as usual but then need to register that class at the end of the file so that it could be instantiated at a later point (without cluttering the namespace) with:
在模型、集合、路由器和视图中,我照常工作,但随后需要在文件末尾注册该类,以便以后可以实例化它(不会使命名空间混乱):
MyApp.reg('Models', 'App', Model);
Does this seem like an unnecessary way to organize code? Do others have better examples of how to organize really large projects with many Routers, Collections, Models and Views?
这似乎是一种不必要的组织代码的方式吗?其他人是否有更好的示例来说明如何组织具有许多路由器、集合、模型和视图的大型项目?
回答by nrabinowitz
I recently worked on a Backbone project called GapVis (code here, rendered content here). I don't know if it's "really large", but it's big-ish and relatively complex - 24 view classes, 5 routers, etc. It might be worth taking a look, though I don't know that all my approaches will be relevant. You can see some of my thinking in the long intro comment in my main app.js file. A few key architectural choices:
我最近参与了一个叫做 GapVis 的 Backbone 项目(代码在这里,渲染内容在这里)。我不知道它是否“真的很大”,但它很大而且相对复杂 - 24 个视图类、5 个路由器等。它可能值得一看,尽管我不知道我所有的方法都是相关的。您可以在我的主 app.js 文件的长介绍性评论中看到我的一些想法。几个关键的架构选择:
I have a singleton
State
model that holds all current state info - the current view, what model ids we're looking at, etc. Every view that needs to modify application state does it by setting attributes on theState
, and every view that needs to respond to the state listens to that model for events. This is even true for views that modify state and update - the UI event handlers inevents
never re-render the view, this is done instead through binding render functions to the state. This pattern really helped to keep views separate from each other - views never call a method on another view.My routers are treated like specialized views - they respond to UI events (i.e. typing in a URL) by updating the state, and they respond to state changes by updating the UI (i.e. changing the URL).
I do several things similar to what you're proposing. My namespace has an
init
function similar to yours, and asettings
object for constants. But I put most of the model and view classes in the namespace as well, because I needed to refer to them in multiple files.I use a registration system for my routers, and considered one for my views, as a nice way to keep the "master" classes (
AppRouter
andAppView
) from having to be aware of every view. In theAppView
case, though, it turned out that order of child views was important, so I ended up hard-coding those classes.
我有一个
State
保存所有当前状态信息的单例模型 - 当前视图、我们正在查看的模型 ID 等。每个需要修改应用程序状态的视图都通过在 上设置属性来完成State
,每个视图都需要响应状态监听该模型的事件。对于修改状态和更新的视图来说也是如此——UI 事件处理程序events
永远不会重新渲染视图,而是通过将渲染函数绑定到状态来完成的。这种模式确实有助于将视图彼此分开 - 视图永远不会调用另一个视图上的方法。我的路由器被视为专门的视图 - 它们通过更新状态来响应 UI 事件(即输入 URL),并且它们通过更新 UI(即更改 URL)来响应状态更改。
我做了几件类似于你提议的事情。我的命名空间有一个
init
和你类似的函数,还有一个settings
常量对象。但我也将大部分模型和视图类放在命名空间中,因为我需要在多个文件中引用它们。我为我的路由器使用了一个注册系统,并为我的视图考虑了一个注册系统,这是一种让“主”类(
AppRouter
和AppView
)不必知道每个视图的好方法。AppView
然而,在这种情况下,子视图的顺序很重要,所以我最终对这些类进行了硬编码。
I'd hardly say that this was the "right" way to do things, but it worked for me. I hope that's helpful - I also had trouble finding visible-source examples of large projects using Backbone, and had to work out most of this as I went along.
我很难说这是做事的“正确”方式,但它对我有用。我希望这会有所帮助 - 我也很难找到使用 Backbone 的大型项目的可见源示例,并且必须在我进行的过程中解决大部分问题。
回答by jaydoubleyou
These 2 resources helped me to setup my backbone apps on a solid basement:
这 2 个资源帮助我在坚固的地下室设置了我的主干应用程序:
回答by Justin wong
In fact, in different ways have advantages and disadvantages of different ways.The most important thing is to find a suitable way of organizing files.The following is the organization of the project I am currently doing. This way the focus will be the same module-related files are placed in a folder. For example: the people module, this module all files are placed in modules / base / people directory. After updating and maintenance of this module, only need to focus on the files in this directory on the line, will not affect files outside the directory, and improved maintainability.
其实不同的方式不同的方式各有优缺点。最重要的是找到合适的文件组织方式。以下是我目前在做的项目的组织方式。这样焦点将相同的模块相关文件放在一个文件夹中。例如:people模块,这个模块的所有文件都放在modules/base/people目录下。本模块更新维护后,只需要关注这个目录下的文件就行了,不会影响目录外的文件,提高了可维护性。
I hope my answer can give you some help, I hope you some valuable advice.
希望我的回答能给你一些帮助,也希望你能提出宝贵的意见。
回答by Mauvis Ledford
I namespace similar to what you're doing (at least for the classes part) and all my models, views, and controllers look like this:
我的命名空间类似于你正在做的事情(至少对于类部分),我所有的模型、视图和控制器看起来像这样:
views/blocks.js:
视图/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);
My JavaScript namespace looks like this, though I do improve upon it every time I build a new app:
我的 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.
}
Anything I want all my views to have, I put in the base view. My controller will call registerEvents
on any new view it creates (after render) and unregisterEvents
on a view right before it kills it. Not all views have these two extra methods so it first checks for the existence.
我希望我的所有视图拥有的任何东西,我都放在基础视图中。我的控制器将调用registerEvents
它创建的任何新视图(渲染后)以及unregisterEvents
在它杀死它之前的视图。并非所有视图都有这两个额外的方法,因此它首先检查是否存在。
Don't forget that all views come with a this.el.remove();
built in. Which not only kills the views container element but unbinds all events attached to it. Depending on how you are creating your views through your controller you may not actually want to kill the element and do this.el.unbind() instead to unbind all events.
不要忘记所有视图都带有this.el.remove();
内置的。这不仅会杀死视图容器元素,还会解除绑定到它的所有事件。根据您通过控制器创建视图的方式,您可能实际上并不想杀死元素并执行 this.el.unbind() 来解除所有事件的绑定。