在重构前端项目的过程中,需要根据主模块动态加载控制器,但Angular要求在开启服务前必须将所有控制器、服务、依赖的模块全部加载完成,下面详细说一下搭建项目过程中的解决方案。
目录结构
main/
controllers/
view/
index.html
app.js
main.js
首先,index.html中主要内容:
<div ng-view></div>
<script data-main="main.js" src="libs/require.js">
在引入main.js后,这时我们在main.js中配置require需要加载的内容:
requirejs.config({
paths: {
jQuery: '../lib/jquery.min',
angular: '../lib/angular.min',
angularRouter: '../lib/angular-route.min',
angularAnimate: '../lib/angular-animate.min'
},
shim: {
'angular': {
deps: ['jQuery'],
exports: 'angular'
},
angularRouter: {
deps: ['angular'],
exports: 'ngRoute'
},
angularAnimate: {
deps: ['angular']
}
}
});
// 手动开启angular服务
require(['angular', 'app'], function(angular){
angular.element(document).ready(function(){
angular.bootstrap(document, ['yceMain']);
});
});
- requireJs的具体用法就不多说了,主要用来配置加载项以及规范。
- angular.bootstrap是手动开启ng服务的选项,就不需要在html代码中加入ng-app指令开启了。
- app.js中的内容接下来会详细说。
app.js中的内容是最精髓最重要的东西:
(define['angular', 'angularRouter'], function(angular){
var yceMain = angular.module('yceMain', ['ngRoute']);
yceMain.config(['$routeProvider', '$controllerProvider', function ($routeProvider, $controllerProvider){
var ctrlRegister = function(ctrlName, ctrlModule) {
return function ($q) {
var defer = $q.defer();
require(ctrlModule, function (controller) {
$controllerProvider.register(ctrlName, controller);
defer.resolve();
});
return defer.promise;
}
};
$routeProvider
.when('/dashBoard', {
templateUrl: 'views/dashBoard.html',
controller: 'dashBoardCtrl',
resolve: {
delay: ctrlRegister('dashBoardCtrl',['controllers/dashBoard.js'])
}
})
.when('/appManage', {
templateUrl: 'views/appManage.html',
controller: 'appManageCtrl',
resolve: {
delay: ctrlRegister('appManageCtrl',['controllers/appManage.js'])
}
})
});
return yceMain;
});
首先使用ngRoute提供的routeProvider服务进行路由配置,resolve是做什么的呢?
- 在页面跳转时,只有当resolve对象中所有的参数都执行resolve()方法后,才会进行页面渲染、实例控制器等操作。
- resolve对象中的参数名称都是由自己定义的,这时会发生一件事情,在实例控制器时,参数名会注入到对应的控制器中。
- resolve一般用来预加载的工作。
下面详细说一下ctrlRegister函数的作用:
var ctrlRegister = function(ctrlName, ctrlModule) {
return function ($q) {
//实例一个promise对象
var defer = $q.defer();
//angular不仅可以通过module去注册控制器
//还可以使用$controllerProvider去注册控制器,如下
require(ctrlModule, function (controller) {
$controllerProvider.register(ctrlName, controller);
//注册成功后,执行defer.resolve(),表示完成一个promise任务
//这个返回值自动赋给defer.promise
defer.resolve();
});
// 每个promise在创建并执行后,必须给调用它的函数返回promise
return defer.promise;
}
};
angular将promise封装在了$q中,$q是angular的一种内置服务,它可以使你异步地执行函数,并且当函数执行完成时它允许你使用函数的返回值(或异常)。
关于promise文档,请看这里。
接下来的事情就比较简单了,在需要加载的controller(dashBoard.js)中这样写:
define(function(){
return function dashBoardCtrl($scope, $http){
// xxx
}
})
这样搭建项目的好处是当点击#/dashBoardsh时,只会加载dashBoard对应的html和controller,节省带宽。