【问题标题】:Backbone Marionette and RequireJS ModulesBackbone Marionette 和 RequireJS 模块
【发布时间】:2012-07-07 00:43:02
【问题描述】:

我正在使用 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
         });
    });

});

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

【问题讨论】:

    标签: javascript backbone.js requirejs marionette


    【解决方案1】:

    Marionette 的模块旨在成为 RequireJS(和其他)模块格式的简单替代品。我不建议将它们一起使用,如 wiki 中所述:

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

    【讨论】:

    • 我不推荐使用多个脚本标签。 BBCloneMail 不是这样做的一个例子。 :) 真实项目具有连接和缩小的构建步骤。 r.js 用于 requirejs 模块,或者可以使用任何其他工具(如 Rails 资产管道或 grunt.js)或许多其他工具来完成。
    • 这里是使用 Marionette 和 RequireJS 的更新链接。 (github 存储库已移动。)github.com/marionettejs/backbone.marionette/wiki/…
    • 现在我可以使用这个答案作为论据,因为它来自 MarionetteJS 创建者。 :)
    • @DerickBailey 使用 Marionette 模块 + RequireJS 不是还有好处吗?即停止模块的能力意味着我们可以释放内存。
    • 关于 AMD 模块与木偶模块的 wiki 文章是否仍然存在于任何地方?我在网上看到了很多对它的引用,但提供的链接不再有效。
    【解决方案2】:

    恕我直言,我喜欢与上述观点不同“Marionette 的模块旨在成为 RequireJS(和其他)模块格式的简单替代方案。”

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

    再次,这是我的观点/理解(基于与 David Sulc 在他的书“使用 RequireJS 和 Marionette 模块构建主干代码”中的讨论),这有助于我的实施。在某种程度上,我们可以将 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 模块和 marionette 模块可以共存。以下是优点。

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

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-08-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-01-01
      • 1970-01-01
      相关资源
      最近更新 更多