最初的源码来自:https://github.com/atian25/angular-lazyload/
但由于一些个人的原因(我有强迫症...)所以把代码的书写风格按照我平日的喜好修改了下
顺便也作了一点小优化,原来的版本,每次回到同一个页面,都会重新执行一次生成对应控制器的 register.controller 方法
但这是大可不必的,理论上每个controller生成一次即可。
在路由处增加 lazyLoadFlag 属性作为检测是否需要异步加载控制器模块 and 对执行之,去除了加载器的 check 方法。
这样一来,某个视图是否需要异步加载控制器模块,就完全由开发者自己通过 lazyLoadFlag 属性进行定义了, lazyLoadFlag 和 controllerUrl 两个属性必须搭配使用,不然会报错。
也顺便认真的阅读了一遍源码,按照自己的理解,把原来的英文注释替换成中文的了
毕竟不是原作者,对ng框架也不是特别的熟,注释中的用词可能有不少不正确的地方,欢迎指出
下面是我稍微修改了一下的代码:
/* * angular-lazyLoad * 一个angular项目的按需异步加载服务模块 * 支持 [Sea.js](http://seajs.org/) & [RequireJS](http://requirejs.org/) */ (function() { 'use strict'; //定义 angular-lazyLoad 模块 & $lazyLoad 服务 angular.module('ngLazyLoad', [], ['$controllerProvider', '$compileProvider', '$filterProvider', '$provide', function ($controllerProvider, $compileProvider, $filterProvider, $provide) { //定义 $lazyLoad 服务 $provide.factory('$lazyLoad', ['$rootScope', '$q', function($rootScope, $q){ /* * 在代码的运行后,你是无法使用 app.controller(...) 方式来定义控制器的 * 只能通过 $controllerProvider.register 方法来定义控制器 * 定义一个 register 对象缓存这些低阶方法,在构造 $lazyLoad 服务对象时作为参数传入 * */ var register = { controller: $controllerProvider.register, directive: $compileProvider.directive, filter: $filterProvider.register, factory: $provide.factory, service: $provide.service, decorator: $provide.decorator }; return new LazyLoadProvider($rootScope, $q, register); }]); } ]); /** * $lazyload 服务类 */ function LazyLoadProvider($rootScope, $q, register){ var _this = this; _this.$$rootScope = $rootScope; _this.$$q = $q; _this.register = register; //为 $rootScope 添加 safeApply 方法 _this.patchScope(); } /** * @param {Object} app 需要异步添加控制器的app主模块 * @param {Function/String} loader 加载器类型,取值范围如下: * - 'seaJS' : 默认值,使用 seaJS 去异步加载模块 * - 'requireJS': 使用 requireJS 去异步加载模块 * - {Object} : 自定义加载器,此对象应该包含一个load方法: * - load {Function} 加载方法,应该包含三个参数:当前路由对象(用来获取controllerUrl属性的值),加载成功回调,加载失败回调 */ LazyLoadProvider.prototype.init = function(app, loader){ //根据loader参数,来决定用什么加载器 var _this = this, _loader = angular.isObject(loader) ? loader : this.loaders[loader] || this.loaders['seaJS']; //给app主模块添加register,以便可以使用低阶方法定义控制器 app.register = _this.register; //监听 $routeChangeStart 事件 _this.$$rootScope.$on('$routeChangeStart', function(event, curRoute){ var route = curRoute && curRoute.$$route; if(route && route.lazyLoadFlag){ route.resolve = route.resolve || {}; /* * 关键点:使用route的resolve对象 * 每当路由变更时,angular都会遍历route的resolve对象的各个属性 * 如果某个是指向一个函数,那么该函数就会被马上执行 */ route.resolve.loadedModule = function(){ var defer = _this.$$q.defer(); _loader.load(route, function(module){ _this.$$rootScope.safeApply(function(){ defer.resolve(angular.isFunction(module) && route.lazyLoadFlag ? module(app) : module); route.lazyLoadFlag = false; }); }, function(module){ _this.$$rootScope.safeApply(function(){ defer.reject(module); }); }); return defer.promise; }; } }); }; //为 $rootScope 增加 safeApply 方法, 安全的apply LazyLoadProvider.prototype.patchScope = function(){ var _this = this; _this.$$rootScope.safeApply = function(fn){ var phase = this.$root.$$phase; if(phase == '$apply' || phase == '$digest'){ if(fn && (typeof(fn) === 'function')){ fn(); } }else{ this.$apply(fn); } }; }; LazyLoadProvider.prototype.loaders = {}; LazyLoadProvider.prototype.loaders['seaJS'] = { load: function(route, suc, fail){ seajs.use(route.controllerUrl, function(module){ if(angular.isUndefined(module)){ fail(module); }else{ suc(module); } }); } }; LazyLoadProvider.prototype.loaders['requireJS'] = { load: function(route, suc, fail){ require(route.controllerUrl, function(module){ if(angular.isUndefined(module)){ fail(module); }else{ suc(module); } }); } }; })();
使用方法和原作也有一丝丝区别,这里也搬一下吧~
1.将代码引入到你的项目页面中去(下面几个基本上可以说是必备的了)
<script src="libs/angular.js"></script>
<script src="libs/angular-route.js"></script>
<script src="libs/angular-lazyLoad.js"></script>
<script src="libs/sea.js" id="seajsnode"></script>
2.手动执行angular.bootstrap
seajs.use("app", function(app){ angular.bootstrap(document, ["app"]); });
3.将ngLazyLoad添加到你的主模块依赖中去
var app = angular.module("app", ["ngLazyLoad", "ngRoute"]);
4.在app.run方法中初始化
app.run(["$lazyLoad", function($lazyLoad){ $lazyLoad.init(app); ... }]);
5.路由映射中,添加 lazyLoadFlag 和 controllerUrl 属性
$routeProvider .when("/login", { controller: "loginCtrl",
lazyLoadFlag: true, controllerUrl: "js/controllers/login.js", templateUrl: "app/templates/login.html" });
6.在你的模块里,通过 app.register.controller 方法来定义控制器
define(function(require, exports, module){ "use strict"; module.exports = function(app){ app.register.controller("loginCtrl", ["$scope", function($scope){
...
}]); } }