我们有个系统是用 angular 开发的,是一个单页面应用,随着系统的迭代,首屏代码已经过于庞大,所以对系统进行改造。
我们主要面临 3 个问题
1. 是否需要模块加载框架?
2. 异步加载回来的页面组件,如何注册?
3. 在什么时机加载页面组件?
针对第一个问题,由于 angular 自身已经有一套模块化方案,再引入模块加载框架有点冗余,而且整体改造量比较大,所以不考虑。
因此只是实现了一个 loadscript 方法,用来加载组件。稍微需要注意的是加载多个文件时候的串并行,和避免页面重复切换时的重复加载。
第二个问题比较蛋疼,angular 有 “启动” 的说法,“启动” 发生在 domcontentloaded 之后,会把所有注入到主模块中的依赖编译一遍。
启动之后再想使用 controller、deractive 等 api,会直接报错
目前来看,解决这个问题,只有一个方法,就是利用主模块的 provider 主动注册 controller,但是由于 provider 不能直接使用,所以我们把它存在主模块下面。
通过存下来的方法,可以用来注册异步加载回来的页面组件。缺点就是这样子所有子页面都挂在主模块下了。
针对第三个问题,由于运营平台是单页面应用,最好的加载时机应该是路由监听到哈希变化时,但是由于我们的路由是写死的静态配置,一开始没找到什么好的办法。
后来发现了这样一个 api
大概是说,在 $routeChangeSuccess 之前,我们还可以做些东西,把加载时机放在这里最适合不过啦
具体实现大概是这样子
至此,这个方案已经通了,剩下什么工作?
1. 整理代码,使代码更通用化,我们以后开发新页面,只需要在路由配置里这样写就可以啦
2. 把现有页面都改造一下,由于之前没有按需加载,不同页面之间的 service 耦合严重,今后我们开发新页面,就要注意不同页面之间共用的 service 最好放在 component 下面
3. 改构建,给路由里的 js 引用换成 cdn 路径。
ZABAKAWIS 2016 年 9 月 28 日
版本号怎么解决呢?
愛你多一點 2015 年 10 月 29 日
不知道 LZ 具体怎么实现的,有一个问题请教,首先我的主模块已经做了类似:
app.controller = $controllerProvider.register; 等这一系列定义,
接着在定义路由时,我的 resolve 这样定义,homeCtrl.js 文件加载进来了,但是 homeCtrl 这个控制器还是没有注册到主模块上,导致依旧提示如下错误:
Error: [ng:areq] Argument ‘homeCtrl’ is not a function, got undefined
$stateProvider.state(“home”, {
url: “/home”,
templateUrl: “js/views/home/index.html”,
controller: “homeCtrl”,
resolve: [‘$ocLazyLoad’,’$q’, function($ocLazyLoad, $q){
var deferred = $q.defer();
$ocLazyLoad.load({
name: “OursLove”,
files: [“js/controllers/homeCtrl.js”]
})
.finally(function(){
deferred.resolve();
});
return deferred.promise;
}]
});
homeCtrl.js 的定义:
define([“app”], function (app) {
//也就是程序加载了 homeCtrl.js 这个文件,但是未执行进这个函数
return app.controller(“homeCtrl”, [“$scope”, “$rootScope”, “$http”, function ($scope, $rootScope, $http) {
$rootScope.headTitle = “HOME”;
}]);
});
愛你多一點 2015 年 10 月 29 日
很用心的给代码做了缩进,可是为什么提交之后缩进没了呢 [疑问]
愛你多一點 2015 年 10 月 29 日
var app = angular.module(“OursLove”, [“ui.router”, “oc.lazyLoad”]);
孙跃 2015 年 11 月 11 日
你用了 ui-router 和 ocLazyLoad 的话,只需要在 resolve 那里直接 return $ocLazyLoad(); 就行了,返回的本来就是个 promise
杨焱 2015 年 10 月 14 日
还是我,之前我也是第一次用 angular 开发项目,也是想着能够按需加载,但是失败了。看了你的文章后也试着实现了下按需加载。但总觉得方法不是最好,能否分享下 bpController 这个方法吗?
TAT.mandyluo 2015 年 10 月 14 日
bpController 只是一个 controller,不同的是使用了之前提到的保存下来的 app.controller
杨焱 2015 年 10 月 15 日
是,我就是想了解下 angular 里怎么通过一个 controller function 来渲染一个模板的,我的做法是 controllerFunction.apply(this, controllerFunction.providers), 但是碰到 $scope,$rootScope 和 $location 这些就有问题了,只好先在我的 bpController 里申明这几个 provider, 再传到 controllerFunction 里,明显这种方法有问题。
TAT.mandyluo 2015 年 10 月 18 日
这个方法并没有问题,我也是这样做的
TAT.mandyluo 2015 年 10 月 18 日
你觉的问题是什么
TAT.mandyluo 2015 年 10 月 14 日
有更好的方法讨论一下吗?
yy 2015 年 10 月 13 日
图片挂了,
TAT.mandyluo 2015 年 10 月 14 日
已修复,谢谢提醒