更新时间:2021-10-13 16:06:13
本文紧接第二部分:《BackboneJS框架的技巧及模式(2)》
作者:chszs,转载需注明。博客主页:http://blog.csdn.net/chszs
当第一次使用Backbone.js开发应用时,典型的视图结构是像这样的:
var View = Backbone.View.extend({
initialize: function(options) {
this.model.on('change', this.render, this);
},
template: _.template($(‘#template’).html()),
render: function() {
this.$el.html(template(this.model.toJSON());
$(‘#a’, this.$el).html(this.model.get(‘a’));
$(‘#b’, this.$el).html(this.model.get(‘b’));
}
});
当我遇到这个问题,我快速用Google搜索了一下,看别人是怎么做的。结果找到了Ian Storm Taylor的博客,“分解Backbone.js渲染方法”,他在其中描述了在模型中监听单个的属性变化,然后仅仅重新渲染相对于视图中属性变化的那部分。Taylor也描述了返回对象的引用,以便单个渲染函数可以很容易的链接在一起。上面的例子现在就可以修改的易于维护、性能也更优。因为我们只需做视图的部分刷新。
var View = Backbone.View.extend({
initialize: function(options) {
this.model.on('change:a', this.renderA, this);
this.model.on('change:b', this.renderB, this);
},
renderA: function() {
$(‘#a’, this.$el).html(this.model.get(‘a’));
return this;
},
renderB: function() {
$(‘#b’, this.$el).html(this.model.get(‘b’));
return this;
},
render: function() {
this
.renderA()
.renderB();
}
});
正如 Jeremy Ashkenas 在 Backbone.js的GitHub问题中所指出的,Backbone.js并没有实施数据模型与视图层之间的真正分隔,除非模型不是引用视图创建的。因为Backbone.js并没有实施任何关注点分隔,所以你应该将其分离吗?我和许多Backbone.js开发人员,如Oz Katz和Dayal,都相信答案毫无疑问是yes:模型与集合,也就是数据层,应该彻底的与绑定它们的视图无关,保持一个清晰的关注点分离。如果你没有遵循关注点分离,你的代码库会很快变成意大利面条式的代码,而实际上是没有人喜欢意大利面条式的代码。
保持模型与视图无关将会帮助你预防意大利面条式的代码,而没有人喜欢意大利面条式的代码!
保持数据层完全与视图层无关,这会使你创建出更具模块化、可重用和可维护的代码库。你可以很容易地在应用程序各个地方重用和扩展模型与集合,而无需考虑它们所绑定的视图。遵循此模式使对项目不熟悉的新手也能迅速深入到代码库,因为他们会确切地知道哪里发生了渲染,业务逻辑存在于哪里。
这个模式也实现了单一职责原则——它规定了每个类应该具有单个职责,而且它的职责应该封装在类中,因为模型与集合负责处理数据,而视图则负责处理渲染。
此模式的***演示是理解整个例子。比如说对搜索页的结果进行排序,搜索页允许用户添加两个不同的过滤类型,foo和bar,每个类型代表不同的过滤规则。那么,你的URL结构应该是这样:
'search/:foo'
'search/:bar'
'search/:foo/:bar'
routes: {
'search/:foo': 'searchFoo',
'search/:bar': 'searchBar',
'search/:foo/:bar': 'search'
},
search: function(foo, bar) {
},
// I know this function will actually still map correctly, but for explanatory purposes, it's left in.
searchFoo: function(foo) {
this.search(foo, undefined);
},
searchBar: function(bar) {
this.search(undefined, bar);
},
上面的代码现在可修改为如下的维护性更强的代码:
routes: {
'base/:foo': 'search',
'base/:bar': 'search',
'base/:foo/:bar': 'search'
},
search: function() {
var foo, bar, i;
for(i = arguments.length - 1; i >= 0; i--) {
if(arguments[i] === 'something to determine foo') {
foo = arguments[i];
continue;
}
else if(arguments[i] === 'something to determine bar') {
bar = arguments[i];
continue;
}
}
},
通常它会对那些Backbone.js新手造成困扰:model.fetch()不会清除你的模型,而是继承模型的属性。因此,假如模型具有属性x、y和z,你取回y和z,那么属性x仍然是模型中的那个x,而属性y和z会被更新。下面的例子说明了这一点:
var Model = Backbone.Model.extend({
defaults: {
x: 1,
y: 1,
z: 1
}
});
var model = new Model();
/* model.attributes yields
{
x: 1,
y: 1,
z: 1
} */
model.fetch();
/* let’s assume that the endpoint returns this
{
y: 2,
z: 2,
} */
/* model.attributes now yields
{
x: 1,
y: 2,
z: 2
} */