我一直在开发Backbone应用程序,我刚刚开始学习使用Backbone和Require.js。
在我正在重构的骨干应用程序中,我定义了这样的命名空间:App.model.repo
。该模型在不同视图中反复使用。我使用一些集合执行相同的操作,例如App.collection.files
。使用初始索引文件请求引导这些模型和集合。
我确实找到了this example,这看起来是获取引导数据的好方法。但是,我正在努力重用/分享这些模型和视图之间的集合。
我可以想到三种可能的解决方案。哪个最好,为什么?或者是否有我完全遗漏的另一种解决方案?
解决方案1
在索引中定义这些常用模块和集合(当它们被引导时),然后将它们作为选项(initialize
)传递给每个Backbone视图。
define(['jquery', 'underscore', 'backbone', 'handlebars', 'text!templates/NavBar.html'],
function($, _, Backbone, Handlebars, template){
return Backbone.View.extend({
template: Handlebars.compile(template),
initialize: function(options){
this.repoModel = options.repoModel; // common model passed in
}
});
}
);
就分离来说,这些看起来很干净,但是可以快速得到时髦,大量的东西都会传遍整个地方。
解决方案2
定义globals
模块,并将常用的模型和集合添加到其中。
// models/Repo.js
define(['backbone'],
function(Backbone){
return Backbone.Model.extend({
idAttribute: 'repo_id'
});
}
);
// globals.js (within index.php, for bootstrapping data)
define(['underscore', 'models/Repo'],
function(_, RepoModel){
var globals = {};
globals.repoModel = new Repo(<?php echo json_encode($repo); ?>);
return globals
}
);
define(['jquery', 'underscore', 'backbone', 'handlebars', 'text!templates/NavBar.html', 'globals'],
function($, _, Backbone, Handlebars, template, globals){
var repoModel = globals.repoModel; // repoModel from globals
return Backbone.View.extend({
template: Handlebars.compile(template),
initialize: function(options){
}
});
}
);
这个解决方案是否打败了AMD的全部观点?
解决方案3
让一些模型和集合返回一个实例,而不是构造函数(有效地使它们成为单例)。
// models/repo.js
define(['backbone'],
function(Backbone){
// return instance
return new Backbone.Model.extend({
idAttribute: 'repo_id'
});
}
);
// Included in index.php for bootstrapping data
require(['jquery', 'backbone', 'models/repo', 'routers/Application'],
function($, Backbone, repoModel, ApplicationRouter){
repoModel.set(<?php echo json_encode($repo); ?>);
new ApplicationRouter({el: $('.site-container')});
Backbone.history.start();
}
);
define(['jquery', 'underscore', 'backbone', 'handlebars', 'text!templates/NavBar.html', 'models/repo'],
function($, _, Backbone, Handlebars, template, repoModel){
// repoModel has values set by index.php
return Backbone.View.extend({
template: Handlebars.compile(template),
initialize: function(options){
}
});
}
);
我担心这可能会使构造函数和实例成为真正的混淆。
结束
如果你读到这里,你真棒!感谢您抽出宝贵时间。
答案 0 :(得分:4)
就我而言,我更喜欢选项3 。虽然为了防止混淆,我将每个单例实例放在名为instances
的自己的文件夹中。此外,我倾向于将model/collection
与instance
模块分开。
然后,我只是打电话给他们:
define([
"instance/photos"
], function( photos ) { /* do stuff */ });
我更喜欢这个选项,因为每个模块都被迫定义其依赖项(例如,通过名称空间不是这种情况)。解决方案2可以完成这项工作,但如果我使用的是AMD,我希望我的模块尽可能小 - 再加上它们很小就可以更容易进行单元测试。
最后,关于单元测试,我可以在单元测试中重新定义实例以使用模拟数据。所以,绝对是选项3。
您可以在我正在使用ATM的开源应用上看到此模式的示例:https://github.com/iplanwebsites/newtab-bookmarks/tree/master/app
答案 1 :(得分:1)
我会看一下这个例子repo https://github.com/tbranyen/github-viewer
这是骨干锅炉板(https://github.com/tbranyen/backbone-boilerplate)
的工作示例Backbone Boiler板块会产生很多不必要的麻烦,但真正有用的是它为开发复杂的javascript应用程序提供了一些明确的常用模式指示。
我会尝试在今天晚些时候回来更具体地回答你的问题(如果有人不打扰我的话):
答案 2 :(得分:1)
我更喜欢解决方案1. avoid using singletons通常都很好,并且使用全局变量也是值得避免的,特别是因为您使用的是RequireJS。
以下是解决方案1的一些优点:
它使视图代码更具可读性。第一次看模块的人可以通过查看它使用的模型的initialize
函数立即看到。如果使用全局变量,则可能会在文件中向下访问500行。
可以更轻松地为视图代码编写单元测试。因为您可以在测试中传递假模型。