假设我正在使用一个返回 JSON 数据的 API,但它具有复杂或可变的结构。例如,字符串值属性可以是纯文本,也可以用语言标记:
/* first pattern */
{ "id": 1,
"label": "a foo"
}
/* second pattern */
{ "id": 2,
"label": [ {"value": "a foo", "lang": "en"},
{"value": "un foo", "lang": "fr"}]
}
在我的客户端代码中,我不想让 View 代码担心标签是否有多种语言版本以及选择哪一种语言等。或者我可能想隐藏详细的 JSON 结构其他原因。因此,我可以使用合适的 API 将 JSON 值包装在一个对象中:
/** Value object for foo instances sent from server */
var Foo = function( json ) {
this.json = json;
};
/** Return a suitable label for this foo object */
Foo.prototype.label = function() {
var i18n = ... ;
if (i18n.prefLang && _.isArray(this.json.label)) // ... etc etc
};
所以这都是非常正常的 value-object pattern ,而且它很有帮助,因为它与特定的 JSON 结构更加解耦,更易于测试,等等。很好。
我目前没有看到解决方法是如何将这些值对象之一与 Backbone 和 Marionette 一起使用。具体来说,我想使用 Foo
对象作为 Backbone Model
的基础,并将其绑定(bind)到 Marionette ItemView
。但是,据我所知,Model
中的值是直接从 JSON 结构获取的 - 我看不到一种方法来识别对象是函数:
var modelFoo = new Backbone.Model( foo );
> undefined
modelFoo.get( "label" ).constructor
> function Function() { [native code] }
所以我的问题是:将 Backbone Model 的属性与给定 JSON 结构的细节(例如复杂的 API 值)解耦的好方法是什么?值对象、模型和 View 可以很好地发挥作用吗?
编辑
让我再添加一个例子,因为我认为上面关注国际化问题的例子仅表达了我的部分担忧。稍微简化一下,在我的领域中,我的水体包括河流、湖泊和潮间带。一个水体关联有一个或多个采样点,每个采样点都有一个最新的样本。这可能会从服务器上的数据 API 返回,如下所示:
{"id": "GB12345678",
"centre": {"lat": 1.2345, "long": "-2.3456"},
"type": "river",
"samplingPoints": [{"id": "sp98765",
"latestSample": {"date": "20130807",
"classification": "normal"}
}]
}
因此,在我的 View 代码中,我可以编写如下表达式:
<%= waterbody.samplingPoints[0].latestSample.classification %>
或
<% if (waterbody.type === "river") { %>
但这将是可怕的,并且如果 API 格式发生变化,很容易被破坏。稍微好一点,我可以将此类操作抽象为模板辅助函数,但它们仍然很难编写测试。我想要做的是有一个值对象类 Waterbody
,以便我的 View 代码可以具有如下内容:
<%= waterbody.latestClassification() %>
我发现 Marionette 的主要问题之一是坚持在传递给 View 的模型上调用 toJSON()
,但也许某些计算属性建议有办法解决那个。
最佳答案
IMO 中最简洁的解决方案是将标签访问器放入模型中而不是 VO 中:
var FooModel = Backbone.Model.extend({
getLabel : function(){
return this.getLocalized("label");
},
getLocalized : function(key){
//return correct value from "label" array
}
});
并让 View 使用 FooModel#getLabel
而不是 FooModel#get("label")
--编辑1
这个库似乎对您的用例也很有趣:Backbone.Schema
它允许您正式声明模型属性的类型,还为本地化字符串提供一些语法糖,并允许您创建由其他属性的值组成的动态属性(称为“计算属性”)。
--编辑2(回应已编辑的问题)
IMO 从服务器返回的 VO 应该包装在模型中,并将该模型传递给 View 。模型实现了 latestClassification
,而不是 VO,这允许 View 直接调用模型上的该方法。
关于backbone.js - 面向对象模型和backbone.js,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18082911/