我正在开发一个木偶应用程序,但主题也涉及raw Backbone。
在我的应用程序中,我有很多收藏。其中,有3个重要的,在整个应用程序中使用(例如用户数据,如名称,它显示在大多数视图中)。主要的问题是:在Backbone/Marionette中保持对集合的引用的最好方法(一个好的模式)是什么?以下是我的一些想法:
- 我应该将它们附加为
Application
对象的属性吗?如果是这样,我必须将Application
对象的引用传递给所有视图,然后视图传递给它们的子视图,子视图传递给子视图,等等。但这似乎是一个蹩脚和丑陋的设计。 相反,我可以单独传递每个集合,但这似乎是更糟糕的解决方案,因为我无法预测哪个(子)视图将需要集合。保持这些嵌套引用的顺序将比传递 - 也可以将
Application
作为单例导入。我使用requireJS,现在大多数模块返回构造函数(视图,模型和集合的构造函数)。现在app模块返回的是Application构造函数,但它可以返回Application对象。然后,如果视图需要从集合中显示一些数据,它可以只需要app模块,这就是全部。 - 最后,基于前面的观点,我认为我可以创建一个集合的普通映射,并使其像以前一样成为单例。这只是为了禁止所有的视图访问
Application
对象,这似乎仍然是一个糟糕的模式。
Application
对象困难得多,我可以传递一次,总是。请提出你认为最好的建议(也欢迎上面的评论点)。我只需要一个好的设计模式。据我所知,木偶文档在这里没有任何建议。
我遵循David Sulc的书《backbone . marionetie .js: A Gentle Introduction》中的建议。(下一本书也介绍了如何用require https://leanpub.com/structuring-backbone-with-requirejs-and-marionette)The构建相同的项目,他使用的代码示例可以在github上找到,所以你可以看看最后的例子,如果你不想买这本书,但我真的推荐它,因为它真的帮助了我如何构建我的项目。
首先,我设置了一个实体模块。文件的结构也遵循如下:我有一个实体文件夹,其中有单独的实体。
每个实体文件涉及该特定实体的所有操作和结构。我喜欢这种方法,因为当我想编辑实体结构或从服务器获取数据的方法时,我只需要去一个地方进行此更改。
与实体的交互通过牵线木偶请求/请求系统处理。通过这种方式,你可以将处理程序暴露给应用程序的其他部分,但它们不需要关心如何处理该请求,只要它带回所需的响应即可。
下面是我的一个实体的例子来展示我的意思-我的应用程序需要一个名为position的集合,在不同的阶段,所以这是在应用程序的早期加载的东西,然后在它的整个生命周期中可用。
//i am using require so i define my app to use
define(["app", ], function(MyApp) {
//All of this will be added to the Entities module so if i want direct access
//i can go Myapp.Entities.whateverEntityIhaveDeclared
MyApp.module("Entities", function(Entities, MyApp, Backbone, Marionette, $, _) {
//model (nothing new here)
Entities.Position = Backbone.Model.extend({
urlRoot: "api/positions",
defaults: {
name: "",
}
});
//collection again nothing new here
Entities.PositionCollection = Backbone.Collection.extend({
url: "api/positions",
model: Entities.Position,
comparator: "name"
});
//an init function to attach a position collection onto Entities module so it can be available throughout my app
var initializePositions = function() {
if (Entities.positions === undefined) {
Entities.positions = new Entities.PositionCollection();
}
};
//
var API = {
//returns a jquery deferred promise so that this request can easily be handled async
loadPositionEntitiesRemote: function() {
//init positions make's sure i have the collectoin avaliable if it
//has not yet been defined
initializePositions();
//setup defer object
var defer = $.Deferred();
//I actually use a custom sever object here when dealing
//with ajax requests
//but because my app always go through this API i can
//easily swap out how the collection is retrieved.
// Here is an example using backbones fetch
Entities.positions.fetch({
success: function() {
defer.resolve();
},
error: function(data) {
defer.reject(data);
}
});
//setup promise to return
var promise = defer.promise();
return promise;
},
//get the positions collection from here i could
//directly access the attributes or add to the collection
refrencePositionEntities: function() {
initializePositions();
return Entities.positions;
},
//get a position from the collection based on id
//
getPositionEntity: function(positionId) {
initializePositions();
return Entities.positions.get(positionId);
}
};
//setup handlers for the app to use
MyApp.reqres.setHandler("position:entities:remote", function() {
return API.loadPositionEntitiesRemote();
});
MyApp.reqres.setHandler("position:entities:refrence", function() {
return API.refrencePositionEntities();
});
MyApp.reqres.setHandler("position:entity", function(id) {
return API.getPositionEntity(id);
});
MyApp.reqres.setHandler("position:entity:new", function(position) {
return new Entities.Position(position);
});
});
return;
});
现在在我的应用程序中使用这个这里有一个例子,现在可以使用
someFunction: function(){
//so early in the app i will get the positions
var positionPromise = MyApp.request("position:entities:remote");
$.when(positionPromise).done(function() {
//do what ever as data has been loaded
}).fail(function(data){
//something failed so handle here might through up an error page but up to you
}).always(function(){
//something to always do no matter if fail or sucess
});
}
anotherFunction: function(){
//later in the app in another controller i might to get the collection
// I could also get it through MyApp.Entities.positions but i rather use the
// API set up so if i ever decided i want to add so checks or something in
// when retrieving the collection its super easy
var positionsCollection = MyApp.request("position:entities:refrence");
}
不确定我是否做了一个很好的工作来解释这一点,但如果你正在寻找一个好的设计的想法在木偶检查这本书,因为它解释这比我刚刚做的要好得多