我是否过度使用Knockout映射插件总是使用它来做我的视图模型
Am I overusing the Knockout mapping plugin by always using it to do my viewmodel?
我仍然在学习Knockout的正确用法,我发现自己很快就摆脱了在设置我的视图模型时输入ko.observable
,而不是仅仅定义一个对象文字并通过映射插件传递它,如
var viewModel = ko.mapping.fromJS(data);
或者至少是将所有数据填充到viewModel的属性中,比如
var viewModel = {
... events etc ... ,
"data": ko.mapping.fromJS(data)
}
老实说,我这样做的主要原因是为了避免重复输入ko.observable
和ko.observableArray
。我只是想弄清楚这是否是一个好方法,如果有任何缺点,放弃具体的var x = ko.observable()
声明在一起。此外,我做这一切的负载,而不是响应任何ajax调用等,这从我可以告诉,是什么映射插件的设计。
在你的knockout工作中,你是否仍然手动声明可观察对象,一个接一个,或者你是否使用了我使用的mapping.fromJS方法?像这样频繁地使用映射插件有什么特别的缺点吗?
编辑:具体的例子在本文中,Steve通过执行
来设置他的viewModelvar initialData = [ { ... } , { ... } ]; // json from the serializer
var viewModel = {
gifts : ko.observableArray(initialData)
};
通常情况下,我只使用ko.mapping.fromJS
对于这种情况,特别是要确保数组中的对象也变成可观察对象。看看他所做的,我的方法似乎有些矫枉过正,增加了一些不必要的开销。
在使用Knockout一段时间后,我注意到映射插件有一些额外的选项,可以让您对映射过程进行更细粒度的控制。
控件类型和生成的属性数量
有几种方法可以实现这一点,我将介绍一些,但最终的结果是你最终得到一个更轻的结果从映射插件,因为一切都是不可观察的。
基本上,你把所有你认为不会改变的东西作为一个普通属性,只把你想观察的特定项目设置为可观察对象。
使mapping
省略某些属性
您可以通过指定ignore
或include
之类的东西使映射插件完全从最终结果中忽略属性。这两种方法都是相同的,只是方式相反。
注意:示例来自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);
控制哪些属性是可观察的或不可观察的
如果你需要包含属性,但你认为它们不需要被观察到(无论出于什么原因),映射插件有一些东西可以帮助你。
映射插件参数: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%控制在映射过程中创建的内容,包括在对象中放置闭包和订阅的能力,那么你需要使用"create"选项。
具有计算属性的普通结果
这里是一个例子,我是从一个ajax调用映射数据到一个具有results
属性的对象。我不想要任何可观察的东西,我只想要一个简单的生成属性,它将由对象上的其他简单属性组成。也许不是最引人注目的例子,但它展示了功能。
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);
};
}
}
}
订阅,闭包和映射,哦,我的
另一种情况是,如果您希望在结果中包含闭包和订阅。这个例子太长了,不能包含在整个例子中,但它是一个车辆品牌/型号层次结构。我想要一个给定的make(父)的所有模型(子)在模型被禁用的情况下都被禁用,我想要通过订阅来实现这一点。
// 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);
};
}
};
总而言之,我发现你很少需要一个对象的100%,你传递给插件,你很少需要它的100%是可观察的。深入挖掘映射配置选项,创建各种复杂和简单的对象。这个想法是只得到你所需要的一切,没有更多或更少。
我给你的建议和我刚刚在https://stackoverflow.com/questions/7499133/mapping-deeply-hierarchical-objects-to-custom-classes-using-knockout-mapping-plug上回答的另一个问题是一样的。
您使用映射插件的理由是合理的,也是我使用的。为什么要输入更多的代码呢?
根据我的淘汰赛经验(总共4个月),我发现我手工做的越少,让淘汰赛例程做他们的事情,我的应用程序似乎运行得越好。我的建议是先尝试最简单的方法。如果它不能满足你的需求,看看简单的方法是如何做它的"事情"的,并确定必须改变什么来满足你的需求。
Allen,我最近学习Knockout.js的经历和你的很相似。我们使用来自服务器的深层分层对象图,我已经定义了显式的可实例化视图模型函数,这些函数保留了它的基本结构。
一开始,我明确地将每个属性定义为相关视图模型上的可观察对象,但这很快就失控了。此外,切换到使用映射插件的一个主要原因是,我们必须频繁地将图的Ajax发布回服务器,在那里它与持久化版本合并,然后在服务器上进行验证,这样可以更改许多属性和修改集合,并且返回一个新的实例作为Ajax结果,它必须与客户端表示重新合并。这变得非常困难,映射插件帮助很大,它允许标识符规范来解析添加/删除/更新,并将更新后的图形重新映射到原始图形上。
通过对子视图模型使用"create"选项,它还有助于原始图形的创建。在每个视图模型构造器中,我接收到对父视图模型的引用以及用于构造子视图模型的数据,然后创建进一步的映射选项,以从传入的子数据创建孙子。
我最近发现的唯一(轻微)缺点是,当做ko.mapping.toJSON时,它不会挂钩到任何toJSON覆盖,你可能已经在视图模型的原型上定义了,以便从序列化中排除属性。我已经能够通过在unmapping中指定ignore选项来解决这个问题,正如Ryan Niemeyer在那篇文章中建议的那样。
总之,我肯定会坚持使用映射插件。Knockout.js规则。
一个更简单但更有用的插件是knockout-data-projections
目前,它还不能处理js到视图模型的映射,但是它可以很好地处理视图模型到js的映射
- Angular没有根据模型更新我的选择元素
- 为什么我的指令(使用链接)没有出现,并允许ng模型看到它
- 在我的php模型中用javascript更改一个html类
- 为什么我的视图模型不起作用
- 在这种情况下,我应该如何在余烬中放置我的模型有很多关系
- 我的html5应用程序无法显示模型
- 当输入键由jquery触发时,我的模型是未定义的
- 命名空间我的骨干模型
- 为什么我的作用域函数没有获取从模型传递的数据
- 如果ng-if的计算结果为false,AngularJS会使我的模型数据无效
- ng模型没有更新我的对象值
- MVC4剃刀在客户端javascript中访问我的模型中的JsonResult数据
- Knockout JS将我的视图模型创建更改为使用映射pulgin
- 为什么我的骨干.js集合重置只是添加 1 个模型
- NodeJS和Express - 将我的控制器和模型分开
- 在我的情况下,ng 模型返回未定义
- 无法在 javascript 中使用我的模型数据
- 我的表单没有将参数存储在模型中
- 为什么我的模型中的默认属性返回未定义
- KnockoutJS 绑定在我的视图模型实际创建之前应用