Una introducción completa a Backbone.Marionette (Parte 2)

 

 

 

  • Clase magistral de tipografía, con Elliot Jay Stocks
  • Smart Interface Design Patterns, 10h video + UX training

  • Índice
    1. ¿Qué son los módulos?
    2. Lecturas adicionales sobre SmashingMag:
    3. Definición del módulo
      1. Definición del módulo estándar
      2. Definiciones divididas
    4. Accediendo a un módulo
    5. Submódulos
      1. Accediendo a submódulos
    6. Iniciar y detener módulos
      1. Arranque automático y manual
    7. Otros eventos y funcionalidad integrada
    8. Cómo podríamos utilizar realmente un módulo
    9. Conclusión

    En la primera parte de esta serie, analizamos la aplicación de Backbone.Marionette. Esta vez, discutiremos el sistema de módulos que se incluye en Backbone.Marionette. Se puede acceder a los módulos a través de la Aplicación, pero los módulos son un tema muy amplio y merecen un artículo dedicado a ellos.

     

    En la primera parte de esta serie, hablamos de Backbone.MarionetteApplication . Esta vez, discutiremos el sistema de módulos que se incluye en Backbone.Marionette. Se puede acceder a los módulos a través de Application, pero los módulos son un tema muy amplio y merecen un artículo dedicado a ellos.

    ¿Qué son los módulos?

    Antes de entrar en detalles sobre cómo usar el sistema de módulos de Marionette, debemos asegurarnos de que todos tenemos una definición decente de módulo. Un módulo es una unidad de código independiente que idealmente hace una cosa . Se puede utilizar junto con otros módulos para crear un sistema completo. Cuanto más independiente sea una unidad de código, más fácilmente podrá intercambiarse o modificarse internamente sin afectar otras partes del sistema.

     

    Lecturas adicionales sobre SmashingMag:

    • Una introducción completa a Backbone.Marionette (Parte 1)
    • Una introducción completa a Backbone.Marionette (Parte 3)
    • Consejos y patrones de Backbone.js
    • Una introducción a JavaScript de pila completa

    Para este artículo, eso es todo lo que necesitamos para definir módulos, pero si desea obtener más información sobre cómo escribir código modular, hay muchos recursos en Internet, de los cuales el capítulo "La mantenibilidad depende de la modularidad " de Aplicaciones de una sola página en La profundidad es una de las mejores que existen.

    Actualmente, el lenguaje JavaScript no tiene ningún método integrado para definir módulos (la próxima versión debería cambiar eso ), pero han surgido muchas bibliotecas para brindar soporte para definir y cargar módulos. Lamentablemente, el sistema de módulos de Marionette no brinda soporte para cargar módulos desde otros archivos, pero ofrece algunas funciones que otros sistemas de módulos no tienen, como la capacidad de iniciar y detener un módulo. Cubriremos más de eso más adelante. Ahora mismo, comenzaremos con la definición de un módulo.

    Definición del módulo

    Comencemos con las definiciones de módulos más básicas. Como se mencionó, se puede acceder a los módulos a través de Application, por lo que debemos crear una instancia de uno de ellos. Entonces podemos usar su modulemétodo para definir un módulo.

    var App = new Backbone.Marionette.Application();var myModule = App.module(‘myModule’);

    Eso es bastante simple, ¿verdad? Bueno, lo es, pero ese es el módulo más simple que podemos crear. Pero ¿qué creamos exactamente? Esencialmente, le dijimos a la aplicación que queremos un módulo básico, sin funcionalidad agregada por nosotros, y que tendrá un nombre myModule(de acuerdo con el argumento que le pasamos module). Pero, ¿qué es un módulo básico? Es una instanciación de un Marionette.Moduleobjeto.

    Moduleviene con un poco de funcionalidad integrada, como eventos (a través de EventAggregator, que discutiremos detalladamente en un artículo posterior), comenzando con inicializadores (como lo Applicationha hecho) y terminando con finalizadores (repasaremos eso en el " Sección Iniciar y detener módulos”).

    Definición del módulo estándar

    Ahora veamos cómo definir un módulo con algunas de nuestras propias funciones.

    App.module("myModule", function(myModule, App, Backbone, Marionette, $, _){ // Private Data And Functions var privateData = "this is private data"; var privateFunction = function(){ console.log(privateData); } // Public Data And Functions myModule.someData = "public data"; myModule.someFunction = function(){ privateFunction(); console.log(myModule.someData); }});

    Como puedes ver, hay muchas cosas ahí. Miremos la línea superior y avancemos hacia abajo. Al igual que antes, llamamos App.moduley proporcionamos un nombre para el módulo. Pero ahora también estamos pasando una función. La función recibe varios argumentos. Apuesto a que puedes descubrir cuáles son, según los nombres que les he dado, pero aún así los explicaré todos:

     

    • myModule es el mismo módulo que estás intentando crear. Recuerde, ya está creado para usted y es una nueva instancia de Module. Probablemente querrás ampliar esto con algunas propiedades o métodos nuevos; de lo contrario, también puedes seguir con la sintaxis corta que no requiere que pases una función.
    • Appes el Applicationobjeto que llamaste module.
    • Backbonees, por supuesto, la referencia a la biblioteca Backbone.
    • Marionettees la referencia a la biblioteca Backbone.Marionette. En realidad, está disponible a través de Backbone, pero esto le permite asignarle un alias y darle un nombre más corto.
    • $es su biblioteca DOM, que será jQuery o Zepto (o posiblemente algo más en el futuro).
    • _es una referencia a Underscore o Lodash, cualquiera que esté usando.

    Después de eso, puedes pasar y usar argumentos personalizados. Repasaremos esto en un momento.

    Normalmente diría que la mayoría de estos argumentos son innecesarios; después de todo, ¿por qué no tendrías acceso a estas referencias? Sin embargo, pude verlos útiles en un par de situaciones:

    • Un minificador puede acortar los nombres de los argumentos, ahorrando algunos bytes.
    • Si está utilizando RequireJS o algún otro cargador de módulos, solo necesita incorporar el Applicationobjeto como una dependencia. El resto estará disponible a través de los argumentos que te proporcione Module.

    De todos modos, volvamos a explicar el resto de lo que sucede en el código anterior. Dentro de la función, puedes utilizar el cierre para crear variables y funciones privadas, que es lo que hemos hecho. También puede exponer datos y funciones públicamente agregándolos como propiedades de myModule. Así es como creamos y ampliamos nuestro módulo. No es necesario devolver nada porque se podrá acceder al módulo directamente a través de App, como explicaré en la sección "Acceso a un módulo" a continuación.

    Nota: Asegúrese de intentar solo agregar propiedades a su modulevariable y no establecerla igual a algo (por ejemplo, myModule = {…}), porque cuando configura su modulevariable a algo, eso cambia a qué hace referencia el nombre de la variable, y ninguno de los Los cambios que especifique se mostrarán en su módulo más adelante.

    Anteriormente, señalé que puedes enviar argumentos personalizados. De hecho, puedes enviar tantos argumentos personalizados como quieras. Eche un vistazo al código siguiente para ver cómo se hace.

    App.module("myModule", function(myModule, App, Backbone, Marionette, $, _, customArg1, customArg2){ // Create Your Module}, customArg1, customArg2);

    Como puede ver, si pasa argumentos adicionales a module, los pasará a la función en la que está definiendo su módulo. Una vez más, el mayor beneficio que veo de esto es ahorrar algunos bytes después de la minificación ; Aparte de eso, no le veo mucho valor.

     

    Otra cosa a tener en cuenta es que la thispalabra clave está disponible dentro de la función y en realidad se refiere al módulo. Esto significa que ni siquiera necesitas el primer argumento, pero perderías la ventaja de la minificación si no usaras el argumento. Reescribamos ese primer código usando thispara que puedas ver que es exactamente igual a myModule.

    App.module("myModule", function(){ // Private Data And Functions var privateData = "this is private data"; var privateFunction = function(){ console.log(privateData); } // Public Data And Functions this.someData = "public data"; this.someFunction = function(){ privateFunction(); console.log(this.someData); }});

    Como puede ver, como no estoy usando ninguno de los argumentos, decidí no enumerar ninguno de ellos esta vez. También debería ser obvio que puedes omitir el primer argumento y simplemente usar this.

    Definiciones divididas

    Lo último que mencionaré sobre la definición de módulos es que podemos dividir las definiciones. No sé exactamente por qué querrías hacer esto, pero es posible que alguien quiera ampliar tus módulos más adelante, por lo que dividir las definiciones podría ayudarles a evitar tocar tu código original. A continuación se muestra un ejemplo de definiciones divididas:

    // File 1App.module("myModule", function(){ this.someData = "public data";});// File 2App.module("myModule", function(){ // Private Data And Functions var privateData = "this is private data"; var privateFunction = function(){ console.log(privateData); } this.someFunction = function(){ privateFunction(); console.log(this.someData); }});

    Esto nos da el mismo resultado que la definición anterior, pero está dividido. Esto funciona porque en , se nos proporciona File 2el módulo que definimos (suponiendo que se ejecutó antes ). Por supuesto, si intenta acceder a una variable o función privada, debe definirse en la definición del módulo donde se usa porque solo está disponible dentro del cierre donde se define.File 1File 1File 2

    Accediendo a un módulo

    ¿De qué sirve crear módulos si no podemos acceder a ellos? Necesitamos poder acceder a ellos para poder utilizarlos. Bueno, en el primer fragmento de código de este artículo, viste que cuando llamé module, asigné su valor de retorno a una variable. Esto se debe a que utilizamos el mismo método para definir y recuperar módulos. Korean Beauty

    var myModule = App.module("myModule");

    Normalmente, si solo está intentando recuperar el módulo, pasará el primer argumento y modulesaldrá y tomará ese módulo por usted. Pero si pasa una función como segundo argumento, el módulo se aumentará con su nueva funcionalidad y aún devolverá su módulo recién creado o modificado. Esto significa que puede definir su módulo y recuperarlo todo con una sola llamada al método.

     

    Sin embargo, esta no es la única forma de recuperar módulos. Cuando se crea un módulo, se adjunta directamente al Applicationobjeto con el que se construyó. Esto significa que también puedes usar la notación de puntos normal para acceder a tu módulo; pero esta vez debe definirse de antemano, de lo contrario volverás undefined.

    // Works but I don't recommend itvar myModule = App.myModule;

    Si bien esta sintaxis es más corta, no transmite el mismo significado a otros desarrolladores. Recomendaría usar modulepara acceder a sus módulos para que sea obvio que está accediendo a un módulo y no a alguna otra propiedad de App. La conveniencia y el peligro aquí es que creará el módulo si aún no existe. El peligro viene si escribes mal el nombre del módulo; no tendrá forma de saber que no obtuvo el módulo correcto hasta que intente acceder a una propiedad que no existe.

    Submódulos

    Los módulos también pueden tener submódulos. Lamentablemente, Moduleno tiene su propio modulemétodo, por lo que no puede agregarle submódulos directamente, pero eso no nos detendrá. En cambio, para crear submódulos, llama modulea App, tal como solía hacerlo; pero para el nombre del módulo, debe colocar un punto ( .) después del nombre del módulo principal y luego colocar el nombre del submódulo.

    App.module('myModule.newModule', function(){ ...});

    Al usar el separador de puntos en el nombre del módulo, Marionette sabe que debería crear un módulo como un submódulo del módulo antes del punto. Lo interesante (y potencialmente peligroso) es que si el módulo principal no se crea en el momento en que llamas a esto, lo creará junto con su submódulo. Esto puede ser peligroso debido al mismo potencial de errores ortográficos que mencioné anteriormente. Podría terminar creando un módulo que no tenía intención de crear y el submódulo se le adjuntaría, en lugar del módulo que pretendía.

    Accediendo a submódulos

    Como antes, se puede acceder a los submódulos de la misma forma en que están definidos, o puede acceder a ellos como propiedades del módulo.

    // These all work. The first example is recommendedvar newModule = App.module('myModule.newModule');var newModule = App.module('myModule').newModule;var newModule = App.myModule.newModule;// These don't work. Modules don't have a 'module' functionvar newModule = App.myModule.module('newModule');var newModule = App.module('myModule').module('newModule');

    Cualquiera de estos métodos para acceder al submódulo funcionará igualmente bien si ya se han creado tanto el módulo como el submódulo.

    Iniciar y detener módulos

    Si leíste el artículo anterior de la serie sobre Application, sabrás que puedes comenzar Applicationcon start. Bueno, iniciar módulos es lo mismo y también se pueden detener con stop.

    Si recuerda (suponiendo que haya leído el artículo anterior), puede agregar inicializadores con addInitializera un Application, y se ejecutarán cuando se inicie (o se ejecutarán inmediatamente si Applicationya se inició). Algunas otras cosas suceden cuando inicias un Application. Aquí están todos los eventos, en orden:

     

    • dispara el initialize:beforeevento,
    • inicia todos los módulos definidos,
    • ejecuta todos los inicializadores en el orden en que fueron agregados,
    • dispara el initialize:afterevento,
    • desencadena el startevento.

    A Modulese comporta de manera muy similar. La cantidad de eventos y algunos de los nombres de los eventos son diferentes, pero en general es el mismo proceso. Cuando se inicia un módulo,:

    • dispara el before:startevento,
    • inicia todos sus submódulos definidos,
    • ejecuta todos sus inicializadores en el orden en que fueron agregados,
    • desencadena el startevento.

    El stopmétodo también es muy similar. Sin embargo, en lugar de agregar inicializadores, debe agregar finalizadores. Esto se hace con addFinalizery pasando una función para que se ejecute cuando stopse llame. A diferencia de los inicializadores, no se pasan datos ni opciones a cada una de las funciones. Cuando stopse llama,:

    • dispara el before:stopevento,
    • detiene sus submódulos,
    • ejecuta sus finalizadores en el orden en que fueron agregados,
    • desencadena el stopevento.

    Los inicializadores y finalizadores no están pensados ​​únicamente para que los utilicen otros. De hecho, son bastante útiles cuando se usan dentro de la definición del módulo. De esta manera, puede definir un módulo dentro de la definición sin crear ningún objeto para su uso, pero luego escribir sus inicializadores para comenzar a crear los objetos y configurarlos, como en el ejemplo siguiente.

    App.module("myModule", function(myModule){ myModule.startWithParent = false; var UsefulClass = function() {...}; // Constructor definition UsefulClass.prototype ... // Finish defining UsefulClass ... myModule.addInitializer(function() { myModule.useful = new UsefulClass(); // More setup }); myModule.addFinalizer(function() { myModule.useful = null; // More tear down });});

    Arranque automático y manual

    Cuando se define un módulo, de forma predeterminada se iniciará automáticamente al mismo tiempo que se inicia su padre (ya sea el Applicationobjeto raíz o un módulo padre). Si un módulo está definido en un padre que ya se inició, se iniciará inmediatamente.

    Puede configurar un módulo para que no se inicie automáticamente cambiando su definición de dos maneras. Dentro de la definición, puede establecer la startWithParentpropiedad de un módulo en false, o puede pasar un objeto (en lugar de una función) que moduletenga una startWithParentpropiedad establecida en falsey una definepropiedad para reemplazar la función normal.

    // Set 'startWithParent' inside functionApp.module("myModule", function(){ // Assign 'startWithParent' to false this.startWithParent = false;});// -- or --// Pass in objectApp.module("myModule", { startWithParent: false, define: function(){ // Define module here }});App.start();// myModule wasn't started, so we need to do it manuallyApp.module('myModule').start("Data that will be passed along");

    Ahora el módulo no se iniciará automáticamente. Debes llamar startmanualmente para iniciarlo, como hice yo en el ejemplo anterior. Los datos que se pasan startpueden ser de cualquier tipo y se pasarán a los submódulos cuando se inicien, a los inicializadores y a los eventos before:starty .start

     

    Como dije, los datos no se transmiten de esta manera cuando llamas stop. Además, stop debe llamarse manualmente y siempre llamará stopa submódulos; No hay forma de evitar esto. Esto tiene sentido porque un submódulo no debería estar ejecutándose cuando su padre no se está ejecutando, aunque hay casos en los que un submódulo debería estar apagado cuando su padre se está ejecutando.

    Otros eventos y funcionalidad integrada

    Mencioné que Moduleviene con algunas funciones integradas, como EventAggregator. Como se mencionó, podemos usar el onmétodo en un módulo para observar eventos relacionados con el inicio y la detención. Eso no es todo. No hay otros eventos integrados, pero un módulo puede definir y desencadenar sus propios eventos. Echar un vistazo:

    App.module('myModule', function(myModule) { myModule.doSomething = function() { // Do some stuff myModule.trigger('something happened', randomData); }});

    Ahora, cada vez que llamemos doSomethingal módulo, se activará el something happenedevento al que puedes suscribirte:

    App.module('myModule').on('something happened', function(data) { // Whatever arguments were passed to `trigger` after the name of the event will show up as arguments to this function // Do something with `data`});

    Esto es muy similar a la forma en que hacemos las cosas con eventos en colecciones, modelos y vistas en el código Backbone normal.

    Cómo podríamos utilizar realmente un módulo

    Los módulos en Marionette definitivamente se pueden usar para definir módulos de manera muy similar a cualquier otra biblioteca de definición de módulos, pero en realidad no fue así como fue diseñado para usarse. Los métodos integrados starty stopson una indicación de esto. Los módulos que incluye Marionette están destinados a representar subsistemas algo grandes de una aplicación. Por ejemplo, veamos Gmail .

    Gmail es una aplicación única que en realidad contiene varias aplicaciones más pequeñas: cliente de correo electrónico, cliente de chat, cliente de teléfono y administrador de contactos. Cada uno de ellos es independiente (puede existir por sí solo), pero todos están dentro de la misma aplicación y pueden interactuar entre sí. Cuando iniciamos Gmail por primera vez, el administrador de contactos no está activo, ni tampoco la ventana de chat. Si tuviéramos que representar esto con una aplicación Marionette, cada una de esas subaplicaciones sería un módulo. Cuando un usuario hace clic en el botón para abrir el administrador de contactos, detendríamos la aplicación de correo electrónico (porque queda oculta, aunque, para acelerar, podríamos mantenerla en funcionamiento y simplemente asegurarnos de que no se muestre en el DOM) e iniciar el administrador de contactos.

    Otro ejemplo sería una aplicación construida en gran medida a partir de widgets. Cada widget sería un módulo que puede iniciar y detener para mostrarlo u ocultarlo. Esto sería como un panel personalizable como iGoogle o el panel en la parte posterior de WordPress.

    Por supuesto, no estamos limitados a usar los módulos de Marionette de esta manera, aunque es difícil usarlo en el sentido tradicional. Esto se debe a que los módulos de Marionette son objetos totalmente instanciados, mientras que los módulos tradicionales son "clases" que están destinadas a la instanciación posterior.

    Conclusión

    ¡Uf! Esa es mucha información. Si has llegado hasta aquí, te felicito (aunque fue mucho más fácil para ti leer esto que para mí escribirlo). De todos modos, espero que hayas aprendido mucho sobre la forma en que Marionette maneja la definición, el acceso, el inicio y la parada de módulos y submódulos. Puede que le resulte una herramienta muy útil o puede optar por ignorar por completo su existencia. Esa es una de las mejores cosas de Backbone y Marionette: la mayoría de sus funciones son en gran medida independientes, por lo que puedes elegir lo que quieres usar.

    Créditos de la imagen en portada: ruiwen

    (al) (ea)

    Explora más en

    • Codificación
    • Marcos
    • javascript





    Tal vez te puede interesar:

    1. ¿Deberían abrirse los enlaces en ventanas nuevas?
    2. 24 excelentes tutoriales de AJAX
    3. 70 técnicas nuevas y útiles de AJAX y JavaScript
    4. Más de 45 excelentes recursos y repositorios de fragmentos de código

    Una introducción completa a Backbone.Marionette (Parte 2)

    Una introducción completa a Backbone.Marionette (Parte 2)

    Clase magistral de tipografía, con Elliot Jay Stocks Smart Interface Design Patterns, 10h video + UX training Índice

    programar

    es

    https://aprendeprogramando.es/static/images/programar-una-introduccion-completa-a-backbone-815-0.jpg

    2024-05-20

     

    Una introducción completa a Backbone.Marionette (Parte 2)
    Una introducción completa a Backbone.Marionette (Parte 2)

    Si crees que alguno de los contenidos (texto, imagenes o multimedia) en esta página infringe tus derechos relativos a propiedad intelectual, marcas registradas o cualquier otro de tus derechos, por favor ponte en contacto con nosotros en el mail [email protected] y retiraremos este contenido inmediatamente

     

     

    Top 20