在重構(gòu)前端項目的過程中,需要根據(jù)主模塊動態(tài)加載控制器,但Angular要求在開啟服務(wù)前必須將所有控制器、服務(wù)、依賴的模塊全部加載完成,下面詳細說一下搭建項目過程中的解決方案。
目錄結(jié)構(gòu)
main/
controllers/
view/
index.html
app.js
main.js
首先,index.html中主要內(nèi)容:
<div ng-view></div>
<script data-main="main.js" src="libs/require.js">
在引入main.js后,這時我們在main.js中配置require需要加載的內(nèi)容:
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服務(wù)
require(['angular', 'app'], function(angular){
angular.element(document).ready(function(){
angular.bootstrap(document, ['yceMain']);
});
});
- requireJs的具體用法就不多說了,主要用來配置加載項以及規(guī)范。
- angular.bootstrap是手動開啟ng服務(wù)的選項,就不需要在html代碼中加入ng-app指令開啟了。
- app.js中的內(nèi)容接下來會詳細說。
app.js中的內(nèi)容是最精髓最重要的東西:
(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服務(wù)進行路由配置,resolve是做什么的呢?
- 在頁面跳轉(zhuǎn)時,只有當resolve對象中所有的參數(shù)都執(zhí)行resolve()方法后,才會進行頁面渲染、實例控制器等操作。
- resolve對象中的參數(shù)名稱都是由自己定義的,這時會發(fā)生一件事情,在實例控制器時,參數(shù)名會注入到對應(yīng)的控制器中。
- resolve一般用來預(yù)加載的工作。
下面詳細說一下ctrlRegister函數(shù)的作用:
var ctrlRegister = function(ctrlName, ctrlModule) {
return function ($q) {
//實例一個promise對象
var defer = $q.defer();
//angular不僅可以通過module去注冊控制器
//還可以使用$controllerProvider去注冊控制器,如下
require(ctrlModule, function (controller) {
$controllerProvider.register(ctrlName, controller);
//注冊成功后,執(zhí)行defer.resolve(),表示完成一個promise任務(wù)
//這個返回值自動賦給defer.promise
defer.resolve();
});
// 每個promise在創(chuàng)建并執(zhí)行后,必須給調(diào)用它的函數(shù)返回promise
return defer.promise;
}
};
angular將promise封裝在了$q中,$q是angular的一種內(nèi)置服務(wù),它可以使你異步地執(zhí)行函數(shù),并且當函數(shù)執(zhí)行完成時它允許你使用函數(shù)的返回值(或異常)。
關(guān)于promise文檔,請看這里。
接下來的事情就比較簡單了,在需要加載的controller(dashBoard.js)中這樣寫:
define(function(){
return function dashBoardCtrl($scope, $http){
// xxx
}
})
這樣搭建項目的好處是當點擊#/dashBoardsh時,只會加載dashBoard對應(yīng)的html和controller,節(jié)省帶寬。