Обеспечивает ли KnockoutJS подходящую архитектуру для создания больших веб-приложений?

Быстрый вопрос:

Обеспечит ли KnockoutJS прочную основу для разработки большого веб-приложения? Я боюсь иметь один огромный viewModel, который станет необслуживаемым.

Справочная информация

Я буду создавать веб-приложение, которое будет в значительной степени основано на клиентской стороне. Бэкенд будет просто конечной точкой RESTful. Весь интерфейс веб-приложения будет построен на чистом HTML/CSS/JS - никаких скриптов на стороне сервера.

Само веб-приложение будет состоять из нескольких небольших приложений с одним общим логином (подобно веб-приложениям Google, где есть Gmail, Docs, Calendar, Reader и т.д.).

Каждое из этих веб-приложений будет иметь общую функциональность (например, древовидный вид боковой панели, вид меню верхней панели, система уведомлений) и некоторые уникальные функции. Обычно я разбиваю свои приложения на части, чтобы инкапсулировать функциональность, примерно так:

var myNamespace = {
    common: {
        settings: {},
        user: {},
        notifications: {}
    },
    app1: {},
    app2: {},
    app3: {}
};

Сейчас мне очень нравится работать с KnockoutJS, и я решил, что он будет полезен при создании некоторых элементов моего проекта (например, системы уведомлений или расширенного представления сетки с автообновлением, поскольку приложение будет поддерживать совместную работу). Но я просто не могу понять, куда поместить мою viewModel в этой структуре.

Я могу найти только тривиальные примеры того, как создавать приложения с помощью KnockoutJS. Можете ли вы построить с его помощью что-то более продвинутое, чем читалка Twitter?Есть ли хорошие примеры того, как разбить много функциональности на viewModel или, возможно, на много viewModel?

Предлагаемое решение

Хотя более теоретический вопрос (вопрос Quick) все еще остается без ответа, я думаю, что нашел решение, которое работает на практике. Ответ @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];
    }
};

Но это лишь небольшое неудобство. Дайте мне знать, что вы думаете!

Edit 1: Может ли решение быть таким же простым, как использование привязки with:? См. раздел "1. Привязки потока управления" для примера.

Правка 2: Я думаю, что моя последняя правка была слишком быстрой. с: Связывание может помочь со структурой вашего кода, но AFAIK оно не помогает вам обмениваться наблюдаемыми между различными частями. Так что предложенное выше решение все еще остается верным.

27
задан Jacob 4 November 2011 в 10:19
поделиться