如何使用requireJs以正确的顺序定义控制器,路由器和应用程序

时间:2012-06-17 08:46:54

标签: javascript backbone.js requirejs marionette

我正在编写一个小应用程序(initApp.jsinitApp.routinj.jsinitApp.controller.js)需要使用require加载哪些模块。
这是我的代码(*)。
在每个模块中使用console.log,我看到模块加载的顺序如下:

1) initController 
2) initRouting 
3) initApp 

这是正确的顺序吗?

现在另一个问题。
initApp.controller.js我需要访问initHeaderinitSidebar(在initApp.js中定义)这样的功能。
但正如您从我的代码(initApp.controller.js)中看到的那样,console.log('initController', app);会返回undefined 为了解决这个问题,我在getApp中定义了函数initApp.controller.js 但肯定有更好的方法来完成这项任务 有什么想法?
感谢

(*)


** main.js **

define([
    'js/app',
    'js/init/initApp',
//    'js/tasks/tasksApp'
],
function (App)
{
    "use strict";
    App.initialize();
});

** initApp.js **

/*global define*/
define([
    'backbone',
    'js/app',
    'js/init/initApp.routing',
    'js/init/views/sidebarView',
    'js/init/views/headerView',
],
function (Backbone, App, Router, SidebarView, HeaderView)
{
    "use strict";
    console.log('initApp', Router)
    var initApp = new Backbone.Marionette.Application({

        initHeader: function ()
        {
            var headerView = new HeaderView();
            App.header.show(headerView);
        },

        initSidebar: function ()
        {
            var sidebarView = new SidebarView();
            App.sidebar.show(sidebarView);
        }

    });

    return initApp;
});

** initApp.routin,js **

/*global define*/
define([
    'backbone',
    'marionette',
    'js/init/initApp.controller'
],
function(Backbone, Marionette, controller)
{
    "use strict";
    console.log('initRouting', controller)
    var Router = Backbone.Marionette.AppRouter.extend({

        appRoutes: {
            '*defaults': 'index'
        }

    });
    return new Router({
        controller: controller
    });

});

** initApp.controller.js **

/*global define*/
define([
    'js/init/initApp'
],
function(app)
{
    "use strict";
    console.log('initController', app); // undefined
    var getApp = function () {
        var initApp;
        require(['js/init/initApp'], function (app) {
            initApp = app;
        });
        return initApp;
    };

    var controller = {
        index: function ()
        {
            var app = getApp();
            app.initHeader();
            app.initSidebar();
        }
    }

    return controller;

});

2 个答案:

答案 0 :(得分:2)

不确定它是否是正确的实现方式,但是,在您的情况下,如果按此顺序加载模块,它将起作用。

1) initApp
2) initController
3) initRouting

所以这意味着你的main.js应该是:

define([
    'js/app',
    'js/init/initApp.routing'
],
function (App)
{
    "use strict";
    App.initialize();
});

答案 1 :(得分:1)

您的文件中存在循环依赖关系:initApp -> initApp.routing -> initApp.controller -> initApp。这就是你得到undefined的原因。

在声明时,当您定义类/对象时,只有在代码中存在依赖关系时,顺序才有意义。在我的例子中,我初始化initApp.js中的路由器和控制器,所以我有:

<强> initApp.js

define(['backbone', 'js/init/initController', 'js/init/initApp.initRouting', ...],
function(Backbone, controller, Router, ...) {
  return {
    initialize: function() {
      // Store a namespaced global reference to my app.
      window.MyApp = new Backbone.Marionette.Application();
      MyApp.addRegions({...});
      MyApp.addInitializers(function(options) {
        MyApp.router =  new Router({controller: controller});
        // Other init stuff...
      });
      MyApp.start();
    }
  };
});

由于我在window.MyApp中存储了对我的应用程序的引用,现在可以在我的JS文件中访问它,而无需任何其他逻辑。例如,我可以直接从控制器或任何视图访问区域:

MyApp.myRegion.show(someView);

所以我的main.js非常小:

require(['app', 'backbone', 'json2'], function(app){
  window.console = window.console || {log: function() {}}; // Needed for IE.
  app.initialize();
});

我的路由器或控制器JS文件都不依赖于彼此或App文件。

<强> initApp.Routing.js

define([
  'jquery',
  'underscore',
  'backbone'
  ], function($, _, Backbone) {
  var Router = Backbone.Marionette.AppRouter.extend({
    appRoutes: {
      // My routes go here...
    }
  });
  return Router;
});

也就是说,我在App中初始化我的路由器,这减少了JS文件之间的依赖关系。

同样,我的控制器只对各种视图和集合有依赖性:

<强> initApp.Routing.js

define([
  'jquery',
  'underscore',
  'backbone',
  'myview',
  'mycollection'
  ], function($, _, Backbone, View, Collection) {
  var controller = {
    showMyView: function() {
      // ...
    }
  });
  return controller;
});

我花了一些时间来解决这个问题是声明和执行之间的区别。只要你只在JS文件中声明东西(即,包装在对象中,或者调用extend),我就可以通过你的main.js'app.initialize()执行一个入口点,你将是安全的,你可以在任何地方访问MyApp个对象。

<强>更新

有关在其他JS文件中获取对应用程序实例的访问权的替代方法,请参阅Access Your Application Instance From Other Modules上更新的Backbone.Marionette wiki。