带有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'] });
事实上,我们只为我们的ControllerNames
和Controller_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") });
我们将如何懒惰地加载控制器? 这已经在ngRoute
certificate了
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阶段,我们要求$controllerProvider
angular度并为其保留参考。
现在让我们继续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(); }]); });