Backbone Marionette和RequireJS模块

时间:2012-07-06 14:29:32

标签: javascript backbone.js requirejs marionette

我正在与Marionette开始大规模的javascript应用程序。 Marionette应用程序具有应用程序模块的概念,RequireJS也用于将代码分解为模块,

目前我已经开始申请了这个:

require([ "jquery", "underscore", "backbone", "marionette" ],
function ($, _, Backbone, Marionette) {
    $(function() {

        App = new Marionette.Application();
        App.addInitializer(function(options) {
            App.addRegions({
                mainArea: "#mainArea"
            });
        });

        App.on("start", function() {
            // done starting up, do stuff here
        });

        App.start();
    });
});

如果我想添加一个视图,我会在文件中执行以下操作吗?

require([ "jquery", "underscore", "backbone", "marionette" ],
function($, _, Backbone, Marionette) {

    App.module("FirstView", function(FirstView, App, Backbone, Marionette, $, _) {
        return Marionette.ItemView.extend({
            //define view stuff in here
         });
    });

});

我不确定如何让这段代码实际运行,非常感谢任何帮助

2 个答案:

答案 0 :(得分:23)

Marionette的模块是RequireJS(和其他)模块格式的简单替代品。我不建议一起使用它们,如维基中所述:

https://github.com/marionettejs/backbone.marionette/wiki/AMD-Modules-vs-Marionette's-Modules

答案 1 :(得分:4)

恕我直言我喜欢与上述观点不同" Marionette的模块是RequireJS(和其他)模块格式的简单替代品。"

我喜欢在Require.js模块和Marionette.js模块之间用C#的汇编和命名空间概念进行比较。 Marionette.js的模块帮助我们根据功能对各种构建块的定义进行分组,而Require.js可用于加载/注入依赖项。

同样,这是我的观点/理解(基于与David Sulc在他的书中讨论'使用RequireJS和Marionette Modules构建骨干代码'),这有助于我的实施。在某种程度上,我们可以一起使用Marionette.js和Require.js,如下所述。

以下示例是一个小型图书馆管理器应用程序(示例),可以在@ https://github.com/srihari-sridharan/LibraryManagement在线找到。下面的代码(省略无关紧要的部分)创建应用程序对象并在初始化后呈现书籍列表。请在此处找到 - 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;
});

接下来,我们根据功能定义模块/子模块。这也将具有模块特定的路由器,并将连接控制器和处理路由。请注意对控制器的require调用。此代码存在于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;
});

最后,我们对视图,模型和控制器进行了定义。这些定义将与模块/子模块对象相关联。

视图代码如下所示。查看.extend()方法。它们被分配给附加到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.
});

控制器代码如下所示。这是从booksModule.js中的代码调用的。控制器定义附加到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模块和牵线木偶模块可以共存。以下是优点。

  • 更清晰的源代码组织和更清晰的关注点分离。
  • 模块启动和停止方法提供了初始化和清理对象的条件。
  • 当您将功能和子功能模型化为模块和子模块时,我们可以更精细地控制驻留在内存中的内容以及不应该内存的内容。
  • 此外,模块定义可以分割为多个文件。

请发表您的想法。谢谢你的阅读。

PS:根据上述观点,请查看以下示例的更改:

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