KnockoutJS是否为构建大型Web应用程序提供了合适的架构?

时间:2011-11-01 08:17:31

标签: architecture knockout.js

快速提问:

Will KnockoutJS将为开发大型网络应用提供坚实基础吗?我害怕有一个巨大的viewModel将变得无法维护。

背景信息

我将构建一个基于客户端的Web应用程序。后端只是一个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无法帮助您在这些不同部分之间共享可观察对象。所以上面提出的解决方案仍然是可行的方法。

4 个答案:

答案 0 :(得分:10)

您可以使用部分视图并在它们之间共享可观察对象。

    var some_observable = ko.observable()

    var Model1 = function(something) {
        this.something_1 = something;
    };
    var Model2 = function(something) {
        this.something_2 = something;
    };

    var view_1 = Model1(some_observable);
    var view_2 = Model2(some_observable);

    ko.applyBindings(view_1, document.getElementById('some-id'));
    ko.applyBindings(view_2, document.getElementById('some-other-id'));

    <div id='some-id'>
        <input data-bind='value: something_1' />
    </div>
    <div id='some-other-id'>
        <input data-bind='value: something_2' />
    </div>

我一直在使用这个方法在图库应用程序中维护列表照片,其中一个视图呈现缩略图,另一个视图负责上传。

答案 1 :(得分:3)

我使用了部分视图(在Nancy而不是MVC中),每个视图都有自己的挖掘任务,每个都有自己的视图模型。我觉得它很漂亮 - 一个复杂的页面分解成许多简单的独立部分。大多数部分视图都有自己的模块/控制器/端点,因此模块也是“瘦”的。

删除jQuery模板真是太遗憾了,但这是一个不同的问题。

对不起,我刚刚重新阅读你的帖子:没有服务器端的东西,所以没办法打破页面?哎哟。我仍然认为很多视图模型都是可行的。

答案 2 :(得分:1)

在我看来,我们可以使用KO并将View Models共享到功能模块的范围(比如具有多个html控件的功能小部件)。我们可以考虑使用TIBCO Page bus(Pub / Sub)在页面中的这些功能模块之间进行通信,以使页面中的功能模块保持分离和可管理的方式。

答案 3 :(得分:0)

这是一篇旧帖子,但最近我在this repository that I call gcc-knockout中为完全相同的目的构建了一个框架。一切都是一个组件,甚至还有一个视图管理器可以完全切换视图并同时保存历史记录。我还没有正确记录它,但是repo附带了一个展示它的一些功能的例子。

请注意,我还使用了Google Closure Compiler。如果您正确导出将在html模板中使用的属性,则可以在高级模式下安全地使用它。组件使用goog.events进行通信,现在一切都很干净。我没有使用knockout的订阅实用程序。随意查看并贡献!我偶尔会更新它。