【发布时间】:2011-12-19 07:42:23
【问题描述】:
快速提问:
KnockoutJS 会为开发大型网络应用程序提供坚实的基础吗?我担心有一个巨大的 viewModel 会变得无法维护。
背景资料
我将构建一个基于客户端的网络应用程序。后端将只是一个 RESTful 端点。 Web 应用程序的整个界面将以纯 HTML/CSS/JS 构建 - 不涉及服务器端脚本。
网络应用程序本身将由几个较小的应用程序组成,只需一个常规登录名(有点像谷歌的网络应用程序,你有 Gmail、文档、日历、阅读器等)。
这些网络应用程序中的每一个都将具有一些通用功能(例如侧边栏树视图、顶部栏菜单视图、通知系统)和一些应用程序独有的功能。通常我会分解我的应用程序以封装功能,例如:
var myNamespace = {
common: {
settings: {},
user: {},
notifications: {}
},
app1: {},
app2: {},
app3: {}
};
现在,我真的很喜欢使用 KnockoutJS 并认为它在构建我的项目的某些元素时会很有帮助(例如通知系统,或者具有自动刷新功能的高级网格视图,因为该应用程序将支持协作)。但我只是不知道将我的 viewModel 放在这个结构中的哪个位置。
我只能找到关于如何使用 KnockoutJS 构建应用程序的简单示例。 你真的可以用它构建比 Twitter 阅读器更高级的东西吗?有没有很好的例子来说明如何将 viewModel 中的许多功能分解,或者分解成许多 viewModel?
建议的解决方案
虽然更理论的问题(快速问题)在这里仍然没有答案,但我想我已经找到了一个在实践中有效的解决方案。 @Simon 的回答让我深思,这就是我目前所得到的:
// First: a collection of Observables that I want to share
ld.collectionOfObservables = {
notifications: ko.observableArray([]),
};
// Now let's define a viewModel. I put all my stuff inside the
// 'ld' namespace to avoid cluttering the global object.
ld.viewModel1 = function (args) {
// Look inside args and bind all given parameters
// Normally you will want args to be an object of Observables.
for (var key in args) {
if (args.hasOwnProperty(key)) {
this[key] = args[key];
}
};
// So, by now we already have some observables in
// 'this', if there were any supplied in 'args'.
// Additionally, we define some model-unique properties/observables
this.folders = [ 'Inbox', 'Archive', 'Sent', 'Spam' ];
this.selectedFolder = ko.observable('Inbox');
};
// *** Let's pretend I create similar class and call it ld.viewModel2 ***
ld.viewModel2 = function (args) { .... }
// OK, now go on and instantiate our viewModels!
// This is the fun part: we can provide 0-many observables here, by providing them in an object
// This way we can share observables among viewModels by simply suppling the same observables to different viewModels
var vm1 = new ld.viewModel1({
notifications: ld.collectionOfObservables.notifications, // we take an Observable that was defined in the collection
});
var vm2 = new ld.viewModel2({
notifications: ld.collectionOfObservables.notifications, // shared with vm1
});
// Of course, we could just send the entire ld.collectionOfObservables as an array
// but I wanted to show that you can be more flexible and chose what to share.
// Not easy to illustrate with *one* shared Observable - notifications -
// but I hope you get the point. :)
// Finally, initiate the new viewModels in a specified scope
ko.applyBindings(vm1, document.getElementById('leftPane'));
ko.applyBindings(vm2, document.getElementById('bottomPane'));
现在,如果 JS 有真正的继承,那就更好了,因为现在我觉得我所有的 viewModel 都以这个开头:
for (var key in args) {
if (args.hasOwnProperty(key)) {
this[key] = args[key];
}
};
但这只是一个小小的不便。让我知道你的想法!
编辑 1:
解决方案可以像使用with: 绑定一样简单吗?示例见“1. Control flow bindings”。
编辑 2:
我认为我的最后一次编辑太快了。 with: 绑定可能有助于您的代码结构,但 AFAIK 它并不能帮助您在这些不同部分之间共享可观察值。所以上面提出的解决方案仍然是要走的路。
【问题讨论】: