Подтвердить что ты не робот

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

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

Будет ли 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 это не поможет вам обмениваться наблюдаемыми между этими разными частями. Таким образом, предлагаемое решение выше по-прежнему остается.

4b9b3361

Ответ 1

Вы можете использовать частичные представления и обмениваться наблюдаемыми между ними.

    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>

Я использую этот aproach для ведения списка фотографий в приложении галереи, где один вид создает эскизы, а другой вид заботится о загрузках.

Ответ 2

Я использовал частичные представления (в Нэнси, а не MVC), каждый из которых имеет свою собственную задачу нокаута, каждая из которых имеет свою собственную модель представления. Я думаю, что он работает красиво - сложная страница разбита на многие простые независимые частичные. Большинство частичных представлений имеют свой собственный модуль/контроллер/конечную точку, поэтому модули тоже "тощие".

Это позор по поводу отбрасывания шаблонов jQuery, но это другая проблема.

Извините, я просто перечитываю ваше сообщение: никаких побочных действий на стороне сервера, так что нет возможности разбить страницу? Уч. Я все еще думаю, что многие модели просмотра - это путь.

Ответ 3

На мой взгляд, мы могли бы использовать KO и делиться View Models с объемом функционального модуля (например, функциональный виджет с несколькими элементами управления html). Мы могли бы изучить TIBCO Page bus (Pub/Sub) для обмена данными между этими функциональными модулями на странице, чтобы поддерживать функциональные модули в развязанной странице и управляемым образом.

Ответ 4

Это старый пост, но недавно я создал фреймворк для той же цели в этот репозиторий, который я называю gcc-нокаутом. Все является компонентом, и даже менеджер представлений может полностью переключать представления и сохранять историю в одно время. Я еще не задокументировал это еще раз, но в репо есть пример, демонстрирующий некоторые его функции.

Обратите внимание, что я также использовал компилятор Google Closure. Вы можете безопасно использовать его в расширенном режиме, учитывая, что вы правильно экспортируете свойства, которые будете использовать в html-шаблонах. Компоненты общаются с помощью goog.events, и все довольно чисто прямо сейчас. Я не использовал утилиту subscribe для подписчиков. Не стесняйтесь проверять и вносить свой вклад! Я иногда обновляю его.