//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 – RequireJS配置:
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文件.而已.此外,我们返回要求应用程序,但是我们将在以后使用不同的功能 – 注册延迟加载的控制器.
deps:[‘app’]是什么意思?首先,我们需要提供文件app.js(‘app’表示find app.js):
define([],function() { var app = angular.module('app'); return app; })
这个返回的值是我们可以在每个异步加载的文件中要求的值
define(['app'],function (app) { // here we would have access to the module("app") });
我们如何懒惰地加载控制器?这在ngRoute已经被证明了
angularAMD is an utility that facilitates the use of RequireJS in AngularJS applications supporting on-demand loading of 3rd party modules such as angular-ui.
我们将要求角度参考$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; } ]);
我们可以看到,我们刚刚创建了应用程序“app”,并创建了持有人app_cached_providers(遵循angularAMD样式).在配置阶段,我们要求角度为$controllerProvider
,并保留参考.
现在我们继续在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; }],}); } ]);
以上部分显示了两个州的声明.其中一个 – “家”是标准的没有懒惰的.它的控制器是隐含的,但可以使用标准.
第二个是状态命名为“other”,其目标是未命名的视图ui-view =“”.在这里我们可以先看看,懒惰的负载.里面的决心(见:)
You can use resolve to provide your controller with content or data that is custom to the state. resolve is an optional map of dependencies which should be injected into the controller.
If any of these dependencies are promises,they will be resolved and converted to a value before the controller is instantiated and the $stateChangeSuccess event is fired.
在我们的套件中,我们知道,一旦解决完成,控制器(以其名称)将在角度存储库中进行搜索:
// 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”将被搜索和加载.这是它的魔法的内容.这里最重要的是使用以前缓存的引用$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()但是
The $controller service is used by Angular to create new controllers. This provider allows controller registration via the
register()
method.
最后还有另一种状态定义,更多的缩小了解决…试图使它更易读:
// 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) { 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); }]);
以上我们可以看到,我们为这个状态的/所有命名视图解析了两个控制器
而已.每个控制器在这里定义
paths: { "TopMenuCtrl": "Controller_TopMenu",... },
将通过resolve和$controllerProvider加载 – 通过RequireJS – 懒惰.检查所有here