2011-11-03 3 views
61

Actualmente estoy trabajando en una gran aplicación web construida en backbone.js y he tenido muchos problemas con la organización, "zombies", etc., así que decidí hacer una refactor principal de código. Ya he escrito un montón de funciones de ayuda para tratar con los "zombis"; sin embargo, me gustaría comenzar desde el principio y crear una buena estructura/organización para el código. No he encontrado muchos ejemplos/tutoriales excelentes sobre la organización backbone.js a gran escala, así que de alguna manera comencé desde cero y me gustaría ver si puedo obtener algunas opiniones sobre dónde comencé.Gran organización de aplicaciones web backbone.js

Obviamente he configurado mi código dentro de un espacio de nombres global; pero también me gustaría mantener ese espacio de nombres bastante limpio. Mi app.js principal mantiene los archivos de clase separados del espacio de nombres global; puede registrar una clase (para que pueda ser instanciada) usando la función reg() y la función inst() crea una instancia de la clase. Así, además de los 3 métodos, el espacio de nombres MiApl solamente tiene Router, Modelo y Vista:

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); 

dentro de los modelos, colecciones, Routers y Vistas, trabajo como de costumbre, pero luego deberá registrar esa clase al final de el archivo de modo que pudiera ser instanciado en un momento posterior (sin saturar el espacio de nombres) con:

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

¿le parece esto como una forma innecesaria para organizar código? ¿Otros tienen mejores ejemplos de cómo organizar proyectos realmente grandes con muchos enrutadores, colecciones, modelos y vistas?

+0

quizá http://codereview.stackexchange.com es más adecuado para este tipo de pregunta - pero nosotros mantener actualizado (enlace post);) – sled

+0

Puede organizar el código en el módulo diferente. Puede consultar https://github.com/juggy/backbone-module Auto-promoción pequeña: p – Julien

Respuesta

32

Recientemente trabajé en un proyecto Backbone llamado GapVis (code here, rendered content here). No sé si es "realmente grande", pero es grande y relativamente complejo: 24 clases de vista, 5 enrutadores, etc. Puede valer la pena echarle un vistazo, aunque no sé si todos mis enfoques serán pertinente. Puedes ver algunos de mis pensamientos en el comentario introductorio largo en mi main app.js file. Unas pocas opciones de arquitectura clave:

  • tengo un modelo Singleton State que contiene toda la información actual estado - la vista actual, lo que los identificadores de modelo que estamos viendo, etc. Cada opinión de que hay que modificar el estado aplicación hace estableciendo atributos en el State, y cada vista que necesita responder al estado escucha ese modelo para eventos. Esto es cierto incluso para las vistas que modifican el estado y la actualización: los manejadores de eventos de IU en events nunca vuelven a renderizar la vista, esto se hace mediante funciones de renderización vinculantes para el estado. Este patrón realmente ayudó a mantener las vistas separadas unas de otras: las vistas nunca llaman a un método en otra vista.

  • Mis enrutadores se tratan como vistas especializadas: responden a eventos de IU (es decir, escribiendo en una URL) actualizando el estado y responden a cambios de estado actualizando la IU (es decir, cambiando la URL).

  • Hago varias cosas similares a las que está proponiendo. Mi espacio de nombres tiene una función init similar a la tuya y un objeto settings para constantes. Pero puse la mayoría de las clases de modelo y vista en el espacio de nombres también, porque necesitaba referirme a ellos en varios archivos.

  • Puedo usar un sistema de registro para mis routers, y considerado como uno de mis puntos de vista, como una buena manera de mantener las clases "maestros" (AppRouter y AppView) de tener que estar al tanto de todas las vistas. Sin embargo, en el caso AppView, resultó que el orden de las vistas de los niños era importante, así que terminé codificando esas clases.

No diría que esta era la forma "correcta" de hacer las cosas, pero funcionó para mí. Espero que sea útil. También tuve problemas para encontrar ejemplos de fuentes visibles de proyectos grandes que usaban Backbone, y tuve que resolver la mayor parte de esto a medida que avanzaba.

+0

Gracias por toda esa información; Me alegro de que ambos tuviéramos procesos de pensamiento similares, al menos confirma que no estoy loco, jaja. Definitivamente me gusta su idea sobre el uso de eventos más a menudo y el uso de enrutadores como simplemente "vistas de URL". Supongo que aún no estoy seguro de si mi sistema de registro para todas las clases vale la pena ... No satura el espacio de nombres global, pero ¿eso importa? ¿Hay problemas de rendimiento asociados con saturar el espacio de nombres MyApp con archivos de clase? – user527480

+0

Creo que probablemente estés pensando demasiado en esa parte, si tu objetivo principal es mantener limpio el espacio de nombres, no hay problemas de rendimiento que conozca, el problema es más sobre la organización del código. Hay un beneficio de compresión al usar 'var MyClass' en lugar de' ns.MyClass', que normalmente no se puede enviar, pero es mínimo, y de todos modos se usan nombres de cadena. – nrabinowitz

5

I espacio de nombres similar a lo que está haciendo (al menos para las clases de parte) y todos mis modelos, vistas y controladores de tener este aspecto:

views/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); 

Mi JavaScript espacio de nombres tiene este aspecto, aunque yo mejorarlo cada vez que voy a construir una nueva aplicación:

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.                               
} 

lo que quiera todos mis puntos de vista a tener, me pone en la vista base. Mi controlador llamará al registerEvents en cualquier vista nueva que cree (después del renderizado) y unregisterEvents en una vista justo antes de que lo mate. No todas las vistas tienen estos dos métodos adicionales, por lo que primero verifica la existencia.

No olvide que todas las vistas vienen con un this.el.remove(); integrado. Esto no solo elimina el elemento contenedor de vistas sino que desvincula todos los eventos asociados. Dependiendo de cómo esté creando sus vistas a través de su controlador, en realidad no desea matar el elemento y hacer esto.el.unbind() para desvincular todos los eventos.

+0

en cuyo caso no querré matar el elemento y hacer esto.el.unbind()? Tengo un método cercano que hace lo siguiente: if (this.onClose) this.onClose(); $ (this.el) .remove(); $ (this.el) .unbind(); – ccsakuweb

+2

'.remove' hace' .unbind' automáticamente, así que deberías estar bien. –

5

De hecho, en diferentes formas tienen ventajas y desventajas de diferentes maneras. Lo más importante es encontrar una forma adecuada de organizar los archivos. La siguiente es la organización del proyecto que estoy haciendo actualmente. De esta forma, el foco será el mismo módulo: los archivos relacionados se colocan en una carpeta. Por ejemplo: el módulo de personas, este módulo, todos los archivos se colocan en el directorio modules/base/people. Después de actualizar y mantener este módulo, solo debe centrarse en los archivos de este directorio en la línea, no afectará los archivos fuera del directorio y la capacidad de mantenimiento mejorada.

Espero que mi respuesta pueda brindarle alguna ayuda, espero que algunos consejos valiosos.

enter image description here

+1

También tengo una carpeta con módulos, pero creo que cada carpeta de módulo necesita la carpeta de modelos y la carpeta de vistas al menos – ccsakuweb

+0

¿Para qué sirve el contexto.js? ¿tienes github? – alejandro

Cuestiones relacionadas