ngLazyLoad——让ng项目实现controllers按需异步加载

最初的源码来自: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){
      ...
    }]);   } }

 

你可能感兴趣的:(controller)