IMHO mi piace differire dal punto di vista sopra indicato "moduli di marionette sono destinate ad essere una semplice alternativa al RequireJS (e altri) formati di modulo. "
Mi piace disegnare un confronto tra i moduli Require.js e i moduli Marionette.js con i concetti di assemblaggio e spazio dei nomi di C#. I moduli di Marionette.js ci aiutano a raggruppare le definizioni di vari elementi costitutivi in base alle funzionalità, mentre Require.js può essere utilizzato per caricare/iniettare dipendenze.
Ancora una volta, questo è il mio punto di vista/comprensione (basato sulle discussioni con David Sulc sul suo libro "Strutturare il codice backbone con RequireJS e moduli Marionette"), che ha aiutato nella mia implementazione. In un modo possiamo utilizzare Marionette.js e Require.js insieme come descritto di seguito.
L'esempio seguente è una piccola app Library Manager (esempio) che può essere trovata online @https://github.com/srihari-sridharan/LibraryManagement. Il codice seguente (omettendo bit e parti non significativi) crea l'oggetto dell'applicazione e restituisce l'elenco dei libri dopo l'inizializzazione. Si prega di trovare qui - https://github.com/srihari-sridharan/LibraryManagement/blob/master/app/js/app.js
define([
'marionette',
'modules/config/marionette/regions/dialog'], function (Marionette) {
// Create the application object
var LibraryManager = new Marionette.Application();
// Add regions to the application object
LibraryManager.addRegions({
//Header
headerRegion: "#header-region",
//Main
mainRegion: "#main-region",
//Footer
footerRegion: "footer-region",
//Overlay Dialog
dialogRegion: Marionette.Region.Dialog.extend({
el:"#dialog-region"
})
});
// Subscribe to Initialize After event.
LibraryManager.on('initialize:after', function() {
if(Backbone.history){
require(['modules/books/booksModule', 'modules/about/aboutModule'], function(){
Backbone.history.start();
if(LibraryManager.getCurrentRoute() === ''){
LibraryManager.trigger("books:list");
}
});
}
});
// Return the application object.
return LibraryManager;
});
Poi si definiscono i/sottomoduli modulo in base alla funzionalità. Questo avrà anche un router specifico per il modulo e collegherà i controller e gestirà i percorsi. Si noti la richiesta di chiamata ai controller. Questo codice è presente in https://github.com/srihari-sridharan/LibraryManagement/blob/master/app/js/modules/books/booksModule.js
define(['app'], function (LibraryManager) {
// Define a new module for Books - BooksModule
LibraryManager.module('BooksModule', function (BooksModule, LibraryManager, Backbone, Marionette, $, _) {
BooksModule.startWithParent = false;
BooksModule.onStart = function() {
console.log('Starting BooksModule.');
};
BooksModule.onStop = function() {
console.log('Stopping BooksModule.');
};
});
// Define a new module for a Router specific to BooksModule
LibraryManager.module('Routers.BooksModule', function (BooksModuleRouter, LibraryManager, Backbone, Marionette, $, _) {
BooksModuleRouter.Router = Marionette.AppRouter.extend({
appRoutes: {
'books': 'listBooks',
'books(?filter:=criterion)': 'listBooks',
'books/:id': 'showBook',
'books/:id/edit': 'editBook'
}
});
var executeAction = function (action, arg) {
LibraryManager.startSubModule('BooksModule');
action(arg);
LibraryManager.execute('set:active:header', 'books');
};
var API = {
// This is where we are using/referring to our controller
listBooks: function (criterion) {
require(['modules/books/list/listController'], function (ListController) {
executeAction(ListController.listBooks, criterion);
});
},
showBook: function (id) {
require(['modules/books/show/showController'], function (ShowController){
executeAction(ShowController.showBook, id);
});
},
editBook: function (id) {
require(['modules/books/edit/editController'], function (EditController) {
executeAction(EditController.editBook, id);
});
}
};
// Navigating routes.
LibraryManager.on('books:list', function() {
LibraryManager.navigate('books');
API.listBooks();
});
LibraryManager.on('books:filter', function(criterion) {
if(criterion){
LibraryManager.navigate('books?filter=' + criterion);
}
else{
LibraryManager.navigate('books');
}
});
LibraryManager.on('book:show', function (id) {
LibraryManager.navigate('books/' + id);
API.showBook(id);
});
LibraryManager.on("book:edit", function(id){
LibraryManager.navigate('books/' + id + '/edit');
API.editBook(id);
});
LibraryManager.addInitializer(function() {
new BooksModuleRouter.Router({
controller: API
});
});
});
return LibraryManager.BooksModuleRouter;
});
Infine abbiamo le definizioni per le nostre opinioni, modelli e controllori. Queste definizioni saranno legate agli oggetti modulo/sotto modulo.
Il codice di visualizzazione è mostrato di seguito. Guarda i metodi .extend(). Sono assegnati alle variabili associate al modulo secondario BooksModule.List.View. https://github.com/srihari-sridharan/LibraryManagement/blob/master/app/js/modules/books/list/listView.js
define(['app',
'tpl!modules/books/list/templates/layout.html',
'tpl!modules/books/list/templates/panel.html',
'tpl!modules/books/list/templates/none.html',
'tpl!modules/books/list/templates/list.html',
'tpl!modules/books/list/templates/listItem.html'],
function (LibraryManager, layoutTemplate, panelTemplate, noneTemplate, listTemplate, listItemTemplate) {
LibraryManager.module('BooksModule.List.View', function(View, LibraryManager, Backbone, Marionette, $, _) {
View.Layout = Marionette.Layout.extend({
template: layoutTemplate,
regions:{
panelRegion: '#panel-region',
booksRegion: '#books-region'
}
});
View.Panel = Marionette.ItemView.extend({
// More code here!
});
View.Book = Marionette.ItemView.extend({
// More code here!
});
var NoBooksView = Marionette.ItemView.extend({
template: noneTemplate,
tagName: "tr",
className: "alert"
});
View.Books = Marionette.CompositeView.extend({
// More code here!
});
});
return LibraryManager.BooksModule.List.View; // Return the definition.
});
Il codice del controller è mostrato di seguito. Questo viene chiamato dal codice in booksModule.js. La definizione del controller è allegata al modulo secondario BooksModule.List.
define(['app', 'modules/books/list/listView'], function (LibraryManager, View) {
LibraryManager.module('BooksModule.List', function (List, LibraryManager, Backbone, Marionette, $, _) {
List.Controller = {
listBooks: function (criterion) {
require(['common/views', 'entities/book'], function (CommonViews) {
var loadingView = new CommonViews.Loading();
LibraryManager.mainRegion.show(loadingView);
var fetchingBooks = LibraryManager.request('book:entities');
var booksListLayout = new View.Layout();
var booksListPanel = new View.Panel();
require(['entities/common'], function (FilteredCollection) {
$.when(fetchingBooks).done(function (books) {
// More code here!
});
if(criterion){
filteredBooks.filter(criterion);
booksListPanel.once('show', function() {
booksListPanel.triggerMethod("set:filter:criterion", criterion);
});
}
var booksListView = new View.Books({
collection: filteredBooks
});
booksListPanel.on('books:filter', function (filterCriterion) {
filteredBooks.filter(filterCriterion);
LibraryManager.trigger("books:filter", filterCriterion);
});
booksListLayout.on("show", function(){
booksListLayout.panelRegion.show(booksListPanel);
booksListLayout.booksRegion.show(booksListView);
});
booksListPanel.on('book:new', function() {
require(["modules/books/new/newView"], function (NewView) {
// More code here!
});
LibraryManager.dialogRegion.show(view);
});
});
booksListView.on('itemview:book:show', function (childView, model) {
LibraryManager.trigger("book:show", model.get('id'));
});
booksListView.on('itemview:book:edit', function(childView, model) {
require(['modules/books/edit/editView'], function (EditView) {
// More code here!
LibraryManager.dialogRegion.show(view);
});
});
booksListView.on("itemview:book:delete", function (childView, model) {
model.destroy();
});
LibraryManager.mainRegion.show(booksListLayout);
});
});
});
}
}
});
return LibraryManager.BooksModule.List.Controller; // Return the definition.
});
require.js Così moduli e moduli marionette possono coesistere. I seguenti sono i vantaggi.
- Organizzazione molto più pulita del codice sorgente e separazione più chiara dei problemi.
- I metodi di avvio e arresto del modulo forniscono la possibilità di inizializzare e ripulire gli oggetti.
- Quando modellate funzionalità e sottofunzionalità come moduli e sottomoduli, abbiamo un controllo più granulare su cosa risiede nella memoria e cosa non dovrebbe.
- Inoltre, la definizione del modulo può essere suddivisa su più file.
Si prega di inviare i vostri pensieri. Grazie per aver letto.
PS: Sulla base della precedente punto di vista, si prega di trovare le modifiche al tuo esempio qui sotto:
require([ "jquery", "underscore", "backbone", "marionette" ],
function($, _, Backbone, Marionette) {
App.module("FirstView", function(FirstView, App, Backbone, Marionette, $, _) {
FirstView.View = Marionette.ItemView.extend({
//define view stuff in here
});
return FirstView.View;
});
});
ha un senso. Grazie! Userò RequireJS, perché presumo che se usassi i moduli Marionette dovrei incollare tutti i miei file applicativi in tag script in testa come in BBCloneMail, sto cercando di evitare di farlo. –
Non è consigliabile utilizzare più tag di script. BBCloneMail non è un esempio di come farlo. :) I progetti reali hanno costruito passi concatenanti e minisiti. r.js fa per i moduli requirejs, o può essere fatto con uno qualsiasi di un certo numero di altri strumenti come la pipeline di asset di Rails o grunt.js, o molti altri strumenti. –
Ecco un collegamento di aggiornamento per l'utilizzo di Marionette con RequireJS. (Il repository github è stato spostato.) Https://github.com/marionettejs/backbone.marionette/wiki/Using-marionette-with-requirejs –