Быстрый вопрос:
Будет ли KnockoutJS обеспечивать прочную основу для разработки веб-приложения большого? Я боюсь, что одна огромная модель обзора станет недостижимой.
Фоновая информация
Я создам веб-приложение, которое будет основано на клиентской стороне. Бэкэнд будет просто конечной точкой RESTful. Весь интерфейс веб-приложения будет построен в чистом HTML/CSS/JS - никаких сценариев на стороне сервера.
Веб-приложение будет состоять из нескольких небольших приложений с одним общим именем входа (вроде веб-приложений Google, где у вас есть Gmail, Документы, Календарь, Reader и т.д.).
Каждое из этих веб-приложений будет иметь некоторые общие функции (например, представление дерева боковой панели, представление верхнего меню панели, система уведомлений) и некоторые уникальные функции приложения. Обычно я нарушаю свои приложения, чтобы инкапсулировать функциональность, например:
var myNamespace = {
common: {
settings: {},
user: {},
notifications: {}
},
app1: {},
app2: {},
app3: {}
};
Теперь мне очень нравится работать с KnockoutJS и полагаю, что это будет полезно при создании некоторых элементов моего проекта (например, системы уведомлений или расширенного представления сетки с автоматическим обновлением, поскольку приложение будет поддерживать сотрудничество). Но я просто не могу понять, куда поместить мой viewModel в эту структуру.
Я могу найти только тривиальные примеры того, как создавать приложения с помощью KnockoutJS. Можете ли вы создать что-то более продвинутое, чем читатель Twitter? Есть ли хорошие примеры того, как разбить множество функций в viewModel или, возможно, на многие viewModels?
Предлагаемое решение
В то время как более теоретический вопрос (Быстрый вопрос) по-прежнему остается без ответа, я думаю, что нашел решение, которое работает на практике. Ответ @Simon дал мне некоторую пищу для размышлений, и вот что у меня до сих пор:
// First: a collection of Observables that I want to share
ld.collectionOfObservables = {
notifications: ko.observableArray([]),
};
// Now let 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 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 было реальное наследование, это было бы еще лучше, потому что сейчас я чувствую, что все мои модели viewModels начинаются с этого:
for (var key in args) {
if (args.hasOwnProperty(key)) {
this[key] = args[key];
}
};
Но это лишь незначительное неудобство. Дайте мне знать, что вы думаете!
Изменить 1:
Может ли решение быть таким же простым, как использование привязки with:
? См. " 1. Связывание потоков управления" для примера.
Изменить 2:
Я думаю, что мое последнее редактирование было слишком быстрым. with:
привязка может помочь в структуре вашего кода, но AFAIK это не поможет вам обмениваться наблюдаемыми между этими разными частями. Таким образом, предлагаемое решение выше по-прежнему остается.