带有requirejs的angular-ui-router,延迟加载控制器

你能帮我理解如何在视图之前的例子中加载控制器吗? 看起来像是在控制器尚未加载的情况下立即加载视图。

//app.js $stateProvider.state('index', { url: "/", views: { "topMenu": { templateUrl: "/Home/TopMenu", controller: function($scope, $injector) { require(['controllers/top-menu-controller'], function(module) { $injector.invoke(module, this, { '$scope': $scope }); }); } } } }); //top-menu-controller.js define(['app'], function (app) { app.controller('TopMenuCtrl', ['$scope', function ($scope) { $scope.message = "It works"; }]); }); //Home/TopMenu <h3>TopMenu</h3> <div ng-controller="TopMenuCtrl"> {{message}} </div> 

我在这里创造了工作的蹲伏者 。

让我们有这个index.html

 <!DOCTYPE html> <html> <head> <title>my lazy</title> </head> <body ng-app="app"> <a href="#/home">#/home</a> // we have three states - 'home' is NOT lazy <a href="#/">#/</a> - index // 'index' is lazy, with two views <a href="#/other">#/other</a> // 'other' is lazy with unnamed view <div data-ui-view="topMenu"></div> <div data-ui-view=""></div> <script src="angular.js"></script> // standard angular <script src="angular-ui-router.js"></script> // and ui-router scritps <script src="script.js"></script> // our application <script data-main="main.js" // lazy dependencies src="require.js"></script> </body> </html> 

让我们观察main.js – RequireJSconfiguration:

 require.config({ //baseUrl: "js/scripts", baseUrl: "", // alias libraries paths paths: { // here we define path to NAMES // to make controllers and their lazy-file-names independent "TopMenuCtrl": "Controller_TopMenu", "ContentCtrl": "Controller_Content", "OtherCtrl" : "Controller_Other", }, deps: ['app'] }); 

事实上,我们只为我们的ControllerNamesController_Scripts.js文件创build别名(path)。 而已。 此外,我们返回到需要的应用程序,但我们将在以后使用不同的function – 注册延迟加载的控制器。

代表deps: ['app']是什么意思? 首先,我们需要提供文件app.js ('app'表示find app.js

 define([], function() { var app = angular.module('app'); return app; }) 

这个返回的值是我们可以在每个asynchronous加载文件中要求的值

 define(['app'], function (app) { // here we would have access to the module("app") }); 

我们将如何懒惰地加载控制器? 这已经在ngRoutecertificate了

angularAMD v0.2.1

angularAMD是一个实用程序,它有助于在AngularJS应用程序中使用RequireJS,从而支持第三方模块(如angular-ui)的按需加载。

我们将询问angular度对$controllerProvider的引用 – 稍后使用它来注册控制器。

这是我们script.js的第一部分:

 // I. the application var app = angular.module('app', [ "ui.router" ]); // II. cached $controllerProvider var app_cached_providers = {}; app.config(['$controllerProvider', function(controllerProvider) { app_cached_providers.$controllerProvider = controllerProvider; } ]); 

我们可以看到,我们只创build了应用程序“app”,并创build了持有者app_cached_providers (遵循angularAMD风格) 。 在configuration阶段,我们要求$controllerProviderangular度并为其保留参考。

现在让我们继续script.js

 // III. inline dependency expression app.config(['$stateProvider', '$urlRouterProvider', function($stateProvider, $urlRouterProvider) { $urlRouterProvider .otherwise("/home"); $stateProvider .state("home", { url: "/home", template: "<div>this is home - not lazily loaded</div>" }); $stateProvider .state("other", { url: "/other", template: "<div>The message from ctrl: {{message}}</div>", controller: "OtherCtrl", resolve: { loadOtherCtrl: ["$q", function($q) { var deferred = $q.defer(); require(["OtherCtrl"], function() { deferred.resolve(); }); return deferred.promise; }], }, }); } ]); 

这部分上面显示了两个状态声明。 其中之一 – 'home'是标准的没有懒惰的。 控制器是隐含的,但可以使用标准。

第二个是名为"other"状态,其目标是未命名的视图ui-view="" 。 在这里,我们可以首先看到懒惰的负载。 里面的决心 (见:)

解决

您可以使用解决scheme为您的控制器提供自定义状态的内容或数据。 resolve是应该注入控制器的依赖关系的可选映射。

如果这些依赖关系中的任何一个都是承诺 ,那么它们将在控制器实例化之前parsing并转换为值,并触发$ stateChangeSuccess事件。

在我们的套件中,我们知道,一旦解决方法完成,控制器(通过其名称)将在angular库中被search:

 // this controller name will be searched - only once the resolve is finished controller: "OtherCtrl", // let's ask RequireJS resolve: { loadOtherCtrl: ["$q", function($q) { // wee need $q to wait var deferred = $q.defer(); // and make it resolved once require will load the file require(["OtherCtrl"], function() { deferred.resolve(); }); return deferred.promise; }], }, 

好,现在,如上所述,主要包含这个别名def

 // alias libraries paths paths: { ... "OtherCtrl" : "Controller_Other", 

这意味着文件“Controller_Other.js”将被search并加载。 这是它的神奇内容。 这里最重要的是使用之前caching的$controllerProvider引用

 // content of the "Controller_Other.js" define(['app'], function (app) { // the Default Controller // is added into the 'app' module // lazily, and only once app_cached_providers .$controllerProvider .register('OtherCtrl', function ($scope) { $scope.message = "OtherCtrl"; }); }); 

诀窍不是使用app.controller()而是

$controllerProvider.Register

Angular使用$控制器服务来创build新的控制器。 该提供程序允许通过register()方法进行控制器注册。

最后还有另一个状态定义,更狭义的解决方法…试图使其更具可读性:

 // IV ... build the object with helper functions // then assign to state provider var loadController = function(controllerName) { return ["$q", function($q) { var deferred = $q.defer(); require([controllerName], function() {deferred.resolve(); }); return deferred.promise; }]; } app.config(['$stateProvider', '$urlRouterProvider', function($stateProvider, $urlRouterProvider) { var index = { url: "/", views: { "topMenu": { template: "<div>The message from ctrl: {{message}}</div>", controller: "TopMenuCtrl", }, "": { template: "<div>The message from ctrl: {{message}}</div>", controller: "ContentCtrl", }, }, resolve : { }, }; index.resolve.loadTopMenuCtrl = loadController("TopMenuCtrl"); index.resolve.loadContentCtrl = loadController("ContentCtrl"); $stateProvider .state("index", index); }]); 

上面我们可以看到,我们为这个状态的两个/所有命名的视图parsing了两个控制器

而已。 每个控制器在这里定义

 paths: { "TopMenuCtrl": "Controller_TopMenu", "ContentCtrl": "Controller_Content", "OtherCtrl" : "Controller_Other", ... }, 

将通过resolve和$controllerProvider – 通过RequireJS – lazily加载。 在这里检查一下

类似的问答: AngularAMD + ui-router +dynamic控制器名称?

在一个项目中,我使用了控制器的延迟加载,并且必须手动调用作用域上的$摘要来使其工作。 我猜这个行为不会随着UI路由器而改变。 你尝试过吗?

 define(['app'], function (app) { app.controller('TopMenuCtrl', ['$scope', function ($scope) { $scope.message = "It works"; $scope.$digest(); }]); });