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

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

Предоставит ли 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'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 было настоящее наследство, это было бы еще лучше, потому что сейчас я чувствую, чтовсе мои viewModels начинаются с этого:

for (var key in args) {
    if (args.hasOwnProperty(key)) {
        this[key] = args[key];
    }
};

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

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

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

Ответы [ 4 ]

10 голосов
/ 01 ноября 2011

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

    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>

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

3 голосов
/ 01 ноября 2011

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

Обидно, что шаблоны jQuery отброшены, но это другая проблема.

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

1 голос
/ 14 июня 2012

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

0 голосов
/ 03 ноября 2015

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...