我过度使用Knockout贴图插件来做我的viewmodel吗?

我仍然在学习Knockout的正确用法,而且我发现自己在设置我的viewmodel的时候很快就会ko.observable ,而只是定义一个对象字面值并通过映射插件传递给它

 var viewModel = ko.mapping.fromJS(data); 

或者至less,沿着将所有数据填充到viewModel的一个属性的东西就像这样

 var viewModel = { ... events etc ... , "data": ko.mapping.fromJS(data) } 

说实话,我一直这样做的主要原因是要ko.observableArray重复键入ko.observableko.observableArray 。 我只是想弄清楚这是否是一个好方法,如果有任何缺点,一起放弃具体的var x = ko.observable()声明。 另外,我正在做这一切的负载,而不是响应任何ajax调用等,从我可以告诉,是映射插件的devise。

在你用knockout工作的时候,你还是一个接一个地手动声明observables,还是用了我使用的mapping.fromJS方法? 像这样经常使用映射插件有什么具体的缺点吗?

编辑:

具体例子

在这篇文章中 ,史蒂夫通过这样做来build立自己的观点模型

 var initialData = [ { ... } , { ... } ]; // json from the serializer var viewModel = { gifts : ko.observableArray(initialData) }; 

通常,我只是使用ko.mapping.fromJS来处理这种情况,特别是要确保数组中的对象也变成了可观察对象。 看他做了什么,我的方法似乎是过度杀伤,并增加了一些不必要的开销。

我的build议,你会相同的另一个问题,我只是回答了在https://stackoverflow.com/questions/7499133/mapping-deeply-hierarchical-objects-to-custom-classes-using-knockout-mapping-plug。;

你使用映射插件的理由是合理的,我使用的。 为什么要input比你更多的代码?

在我的淘汰赛(所有4个月)的经验中,我发现我手动做的越less,让淘汰赛惯例做的事情越好,我的应用程序似乎运行。 我的build议是先尝试最简单的方法。 如果它不能满足你的需求,看看简单的方法是如何做的“事情”,并确定必须改变以满足你的需求。

使用Knockout一段时间后,我注意到映射插件有一些额外的选项,可以使您对映射过程进行更精细的控制。

控制types和产生的属性的数量

有几种方法可以完成这个任务,我会介绍一些,但最终的结果是,最终得到一个来自映射插件的更简单的结果,因为一切都是不可观察的。

基本上,你把所有你认为不会改变的东西当作一个普通的财产,只能从你想观察的特定项目中做出可观察的事情。

使mapping省略某些属性

您可以通过指定诸如ignoreinclude类的东西来使映射插件完全从最终结果中省略属性。 这两者都以相反的方式完成同样的事情。

注意:示例来自knockout.js映射插件文档 ,由我添加的注释

映射插件参数: include

以下片段将省略源对象中除通过include参数传入的属性外所有属性

 // specify the specific properties to include as observables in the end result var mapping = { // only include these two properties 'include': ["propertyToInclude", "alsoIncludeThis"] } // viewModel will now only contain the two properties listed above, // and they will be observable var viewModel = ko.mapping.fromJS(data, mapping); 

映射插件参数: ignore

如果您只想从源对象中省略某些属性 ,请使用如下所示的ignore参数。 除了指定的属性之外,它将从源对象中的所有属性进行观察。

 // specify the specific properties to omit from the result, // all others will be made observable var mapping = { // only ignore these two properties 'ignore': ["propertyToIgnore", "alsoIgnoreThis"] } // viewModel will now omit the two properties listed above, // everything else will be included and they will be an observable var viewModel = ko.mapping.fromJS(data, mapping); 

控制哪些属性是或不是可观察的

如果你需要包含属性,但是你不认为它们需要被观察(不pipe出于什么原因),映射插件有一些可以帮助的。

映射插件参数: copy

如果您希望映射插件只复制普通属性而不使其可见,请使用此参数,如下所示。

 // tell the mapping plugin to handle all other properties normally, // but to simply copy this property instead of making it observable var mapping = { 'copy': ["propertyToCopy"] } var viewModel = ko.mapping.fromJS(data, mapping); 

获得对映射过程的完全控制

如果您希望100%控制映射过程中创build的内容, 包括将闭包和订阅放置在对象中的function ,那么您需要使用“创build”选项。

带有计算属性的简单结果

下面是一个例子,我将ajax调用的数据映射到带有results属性的对象。 我不想要任何可观察的东西,我只想要一个简单的生成的属性,将由对象的其他简单的属性。 也许不是最引人注目的例子,但它演示了function。

 var searchMappingConfig = { // specific configuration for mapping the results property "results": { // specific function to use to create the items in the results array "create": function (options) { // return a new function so we can have the proper scope/value for "this", below return new function () { // instead of mapping like we normally would: ko.mapping.fromJS(options.data, {}, this); // map via extend, this will just copy the properties from the returned json element to "this" // we'll do this for a more light weight vm since every last property will just be a plain old property instead of observable $.extend(this, options.data); // all this to add a vehicle title to each item this.vehicleTitle = this.Year + "<br />" + this.Make + " " + this.Model; }, this); }; } } } 

订阅和closures和映射,哦,我的

另一种情况是,如果你想在你的结果中closures和订阅。 这个例子太长而不能被包括在内,而是用于车辆制造/模型层次结构。 如果模型未启用,我希望给定make(parent)的所有模型(子代)都是未启用的,我希望这样做是通过订阅完成的。

 // here we are specifying the way that items in the make array are created, // since makes has a child array (Models), we will specify the way that // items are created for that as well var makesModelsMappingConfig = { // function that has the configuration for creating makes "create": function (options) { // return a new function so we can have the proper // scope/value for "this", below return new function () { // Note: we have a parent / child relationship here, makes have models. In the // UI we are selecting makes and then using that to allow the user to select // models. Because of this, there is going to be some special logic in here // so that all the child models under a given make, will automatically // unselect if the user unselects the parent make. // make the selected property a private variable so it can be closure'd over var makeIsSelected = ko.protectedComputed(false); // expose our property so we can bind in the UI this.isSelected = makeIsSelected; // ... misc other properties and events ... // now that we've described/configured how to create the makes, // describe/configure how to create the models under the makes ko.mapping.fromJS(options.data, { // specific configuration for the "Models" property "Models": { // function that has the configuration for creating items // under the Models property "create": function (model) { // we'll create the isSelected as a local variable so // that we can flip it in the subscription below, // otherwise we wouldnt have access to flip it var isSelected = ko.protectedComputed(false); // subscribe to the parents "IsSelected" property so // the models can select/unselect themselves parentIsSelected.current.subscribe(function (value) { // set the protected computed to the same // value as its parent, note that this // is just protected, not the actual value isSelected(value); }); // this object literal is what makes up each item // in the Models observable array return { // here we're returning our local variable so // we can easily modify it in our subscription "isSelected": isSelected, // ... misc properties to expose // under the item in the Model array ... }; } } }, this); }; } }; 

总而言之,我发现,你很less需要100%的对象,你会传递给插件,你很less需要100%的可观察。 挖掘映射configuration选项,并创build各种复杂和简单的对象。 这个想法是只得到你需要的一切,没有什么或多或less的。

艾伦,我最近的Knockout.js的学习经验和你的相似。 我们使用来自服务器的深层次的对象图,并且定义了显式的可实例化的视图模型函数,它保留了它的基本结构。

我首先明确地将每个属性定义为相关视图模型中的可观察对象,但这很快就失去了控制。 此外,切换到使用映射插件的一个主要原因是,我们必须将图的频繁Ajaxpost发回服务器,在那里与持久化版本合并,然后在服务器上进行validation,使得大量属性可以更改和集合被修改,并且新的实例作为Ajax结果返回,必须重新合并客户端表示。 这变得非常困难,映射插件通过允许指定用于parsing添加/删除/更新的标识符并将更新的graphics重新映射到原始文件上来帮助了大部分时间。

它还通过使用子视图模型的“创build”选项来帮助创build原始graphics。 在每个视图模型构造函数中,我接收到对父视图模型的引用以及用于构造子视图模型的数据,然后创build进一步的映射选项以从传入的子数据创build孙子。

我最近发现的唯一(轻微的)缺点是,在做这个问题的时候 ,是在做ko.mapping.toJSON的时候,它并没有绑定到你可能已经在视图模型的原型上定义的任何toJSON覆盖,以便排除属性从序列化。 我已经能够解决这个问题,通过指定忽略选项,在Ryan Niemeyer的推荐下,在这个职位。

所以总之,我一定会坚持使用地图插件。 Knockout.js规则。

一个更简单但帮助全面的插件可能是淘汰赛的数据投影

目前,它不处理js查看模型映射,但它处理相当好的JS映射的视图模型。