Большая организация веб-приложений backbone.js - PullRequest
61 голосов
/ 04 ноября 2011

В настоящее время я работаю над большим веб-приложением, созданным на основе backbone.js, и у меня было много проблем с организацией, "зомби" и т. Д., Поэтому я решил сделать серьезный рефакторинг кода.Я уже написал кучу вспомогательных функций для работы с «зомби»;Тем не менее, я хотел бы начать с самого начала и создать хорошую структуру / организацию для кода.Я не нашел много хороших учебных пособий / примеров по крупномасштабной организации backbone.js, поэтому я начал с нуля и хотел бы узнать, смогу ли я получить некоторые мнения о том, с чего я начал.

Я, очевидно, настроил свой код в глобальном пространстве имен;но я также хотел бы сохранить это пространство имен довольно чистым.Мой основной app.js хранит файлы классов отдельно от глобального пространства имен;Вы можете зарегистрировать класс (чтобы его можно было создать) с помощью функции reg (), а функция inst () создает экземпляр класса из массива классов.Таким образом, помимо трех методов, пространство имен MyApp имеет только Маршрутизатор, Модель и Представление:

var MyApp = (function () {

    var classes = {
        Routers: {},
        Collections: {},
        Models: {},
        Views: {}
    };

    methods = {

        init: function () {
            MyApp.Router = MyApp.inst('Routers', 'App');
            MyApp.Model = MyApp.inst('Models', 'App');
            MyApp.View = MyApp.inst('Views', 'App');
            Backbone.history.start();
        },

        reg: function (type, name, C) {
            classes[type][name] = C;
        },

        inst: function (type, C, attrs) {
            return new classes[type][C](attrs || {});
        }

    };

    return methods;

}());

$(MyApp.init);

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

MyApp.reg('Models', 'App', Model);

Похоже ли это на ненужный способ организации кода?У других есть лучшие примеры того, как организовать действительно большие проекты с большим количеством маршрутизаторов, коллекций, моделей и представлений?

Ответы [ 4 ]

32 голосов
/ 04 ноября 2011

Я недавно работал над проектом Backbone под названием GapVis (код здесь , отображал контент здесь ).Я не знаю, действительно ли он «действительно большой», но он большой и относительно сложный - 24 класса просмотра, 5 маршрутизаторов и т. Д. Возможно, стоит взглянуть, хотя я не знаю, все ли мои подходы будутСоответствующий.Вы можете увидеть некоторые мои мысли в длинном вступительном комментарии в моем основном файле app.js .Несколько ключевых архитектурных решений:

  • У меня есть одноэлементная модель State, которая содержит всю информацию о текущем состоянии - текущее представление, идентификаторы моделей, на которые мы смотрим, и т. Д. Каждое представлениекоторый должен изменить состояние приложения, делает это, устанавливая атрибуты на State, и каждое представление, которое должно реагировать на состояние, слушает эту модель для событий.Это даже верно для представлений, которые изменяют состояние и обновляют - обработчики событий пользовательского интерфейса в events никогда не перерисовывают представление, это делается вместо этого посредством привязки функций визуализации к состоянию.Этот шаблон действительно помог сохранить представления отдельно друг от друга - представления никогда не вызывают метод в другом представлении.

  • Мои маршрутизаторы обрабатываются как специализированные представления - они реагируют на события пользовательского интерфейса (т.е. вводятURL) путем обновления состояния, и они реагируют на изменения состояния путем обновления пользовательского интерфейса (т. е. изменения URL).

  • Я делаю несколько вещей, аналогичных тому, что вы предлагаете.Мое пространство имен имеет функцию init, аналогичную вашей, и объект settings для констант.Но я также поместил большинство классов моделей и представлений в пространство имен, потому что мне нужно было ссылаться на них в нескольких файлах.

  • Я использую систему регистрации для своих роутеров и считал ее для своих представлений хорошим способом уберечь "мастер" классы (AppRouter и AppView) отбыть в курсе каждого взгляда.Однако в случае AppView оказалось, что порядок дочерних представлений важен, поэтому я в итоге жестко закодировал эти классы.

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

13 голосов
/ 24 апреля 2012

Эти 2 ресурса помогли мне настроить базовые приложения на прочном основании:

5 голосов
/ 20 июня 2012

На самом деле по-разному имеют свои преимущества и недостатки по-разному. Самое главное - найти подходящий способ организации файлов. Ниже приведена организация проекта, которым я сейчас занимаюсь.Таким образом, в центре внимания будут те же файлы, связанные с модулем, которые помещаются в папку.Например: модуль people, все файлы этого модуля размещаются в каталоге modules / base / people.После обновления и обслуживания этого модуля нужно только сосредоточиться на файлах в этом каталоге в строке, это не повлияет на файлы вне каталога и улучшит удобство обслуживания.

Надеюсь, мой ответ может дать вамнекоторая помощь, я надеюсь, что вы несколько ценных советов.

enter image description here

5 голосов
/ 13 ноября 2011

Я называю пространство имен похожим на то, что вы делаете (по крайней мере, для части классов), и все мои модели, представления и контроллеры выглядят так:

просмотров / blocks.js:

(function(cn){
    cn.classes.views.blocks = cn.classes.views.base.extend({

        events: {},

        blocksTemplate: cn.helpers.loadTemplate('tmpl_page_blocks'),

        initialize: function(){
        },

        render: function(){
            $(this.el).html(this.blocksTemplate());
        },

        registerEvents: function(){},
        unregisterEvents: function(){}
    });
})(companyname);

Мое пространство имен JavaScript выглядит следующим образом, хотя я улучшаю его каждый раз, когда создаю новое приложение:

 companyname:{                                                                                                                                                                                 
   $: function(){},      <== Shortcut reference to document.getElementById                                                                                                                      
   appView: {},          <== Reference to instantiated AppView class.                                                                                                                           
   classes = {           <== Namespace for all custom Backbone classes.                                                                                                                         
     views : {},                                                                                                                                                                                
     models : {},                                                                                                                                                                               
     collections: {},                                                                                                                                                                           
     controllers : {},                                                                                                                                                                          
     Router: null                                                                                                                                                                               
   },                                                                                                                                                                                           
   models: {},          <== Instantiated models.                                                                                                                                                
   controllers: {},     <== Instantiated controllers.                                                                                                                                           
   router: {},          <== Instantiated routers.                                                                                                                                               
   helpers: {},         <== Reusable helper platform methods.                                                                                                                                   
   currentView: {},     <== A reference to the current view so that we can destroy it.                                                                                                          
   init: function(){}   <== Bootstrap code, starts the app.                                                                                                                           
 } 

Все, что я хочу, чтобы все мои виды имели, я помещаю в базовый вид. Мой контроллер будет вызывать registerEvents для любого нового представления, которое он создает (после рендеринга), и unregisterEvents для представления непосредственно перед тем, как его убить. Не у всех представлений есть эти два дополнительных метода, поэтому он сначала проверяет существование.

Не забывайте, что все представления имеют встроенный this.el.remove();, который не только убивает элемент контейнера представлений, но и отменяет привязку всех событий, связанных с ним. В зависимости от того, как вы создаете свои представления через контроллер, вы можете не захотеть убивать элемент и вместо этого сделать this.el.unbind (), чтобы отменить привязку всех событий.

...