AngularJS原生并不支持动态加载Controller的方法,但是却提供注册Controller的方法。接下来就来看下如何实现动态加载Controller。
我们把实现动态加载Controller方法封装到一个通用的模块里面,并命名这个模块为ngCommon
。
1 2 3 4
| (function (angular) {'use strict'; var CommonApp = angular.module('ngCommon'); ... })(angular);
|
接下来我们实现一个动态加载js的方法$require
。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
| var loaded = {};
var checkLoaded = function (url) { return !url || !angular.isString(url) || loaded[url]; };
CommonApp.factory('$require', ['$document', '$q', '$rootScope', function ($document, $q, $rootScope) { return function (url) { var script = null; var onload = null; var doc = $document[0]; var body = doc.body; var deferred = $q.defer(); if (checkLoaded(url)) { deferred.resolve(); } else { script = doc.createElement('script'); onload = function (info) { if (info === 1) { deferred.reject(); } else { loaded[url] = 1; $rootScope.$evalAsync(function () { deferred.resolve(); }); } script.onload = script.onerror = null; body.removeChild(script); script = null; }; script.onload = onload; script.onerror = function () { onload(1); }; script.async = true; script.src = url; body.appendChild(script); } return deferred.promise; }; }]);
|
然后重点来了,通过$routeProvider route
的resolve
功能来实现动态加载Controller。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| CommonApp.provider('$routeResolver', function () { this.$get = function () { return this; }; this.route = function (routeCnf) { var controller = routeCnf.controller; var controllerUrl = routeCnf.controllerUrl; if (controllerUrl) { routeCnf.reloadOnSearch = routeCnf.reloadOnSearch || false; routeCnf.resolve = { load: ['$route', '$require', 'ControllerChecker', function ($route, $require, ControllerChecker) { var controllerName = angular.isFunction(controller) ? controller($route.current.params) : controller; var url = angular.isFunction(controllerUrl) ? controllerUrl($route.current.params) : controllerUrl; if (checkLoaded(url) || (controllerName && ControllerChecker.exists(controllerName))) { loaded[url] = true; return; } return $require(url); }] }; } return routeCnf; }; })
|
看上面的代码中还注入了一个叫ControllerChecker
的,这个是用来检测当前Controller是否已经注册了,如果未注册,那么我们就加载相关js注册新的Controller。代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| CommonApp.service('ControllerChecker', ['$controller', function ($controller) { return { exists: function (controllerName) { if (angular.isFunction(window[controllerName])) { return true; } try { $controller(controllerName, {}, true); return true; } catch (e) { return false; } } }; }]);
|
最后我们来添加一个注动态册的方法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| CommonApp.setupRegister = function (module) { module.config([ '$controllerProvider', '$compileProvider', '$filterProvider', '$provide', function ($controllerProvider, $compileProvider, $filterProvider, $provide) { module.register = { controller: $controllerProvider.register, directive: $compileProvider.directive, filter: $filterProvider.register, factory: $provide.factory, service: $provide.service, value: $provide.value, constant: $provide.constant }; } ]); };
|
到此已经基本完成了,如何使用呢?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| var DemoApp = angular.module('DemoApp',['ngRoute','ngCommon']);
angular.module('ngCommon').setupRegister(DemoApp); DemoApp.config(['$routeProvider', '$routeResolverProvider', function ($routeProvider, $routeResolverProvider) { var route = $routeResolverProvider.route; $routeProvider.when('/index', route({ templateUrl: './view/index.html'), controller: 'IndexController', controllerUrl: './controller/index.js') })) .otherwise('/index');
DemoApp.register.controller('IndexController', ['$scope', '$require', function($scope, $require) { ... $require(url).then(function () { ... }); }]);
|