AngularJS能够很好地与RequireJS(http://www.requirejs.org/)配合使用,这使得我们可以同时拥有两种组件的优点。下面通过配置AngularJS官方的AngularSeed实例,来看一下AngularJS与RequireJS集成组织项目的方式。
项目结构:
首先,我们需要main.js文件,RequireJS将会加载这份文件,然后这份文件将会触发加工其他所有依赖的东西。
main.js
/** * 定义RequireJS配置
*/
require.config({
paths: {
'angular': '../lib/angular/angular',
'angular-route': '../lib/angular-route/angular-route',
'domReady': '../lib/requirejs-domready/domReady'
},
shim: {
'angular': {
exports: 'angular'
},
'angular-route': {
deps: ['angular']
}
},
deps: [
// kick start application... see bootstrap.js
'./bootstrap'
]
});
require( [
'app',
//注意:这不是Twitter Bootstrap,而是AngularJS bootstrap
'bootstrap',
//所创建的所有控制器、服务、指令及过滤器文件都必须写到这里,这块内容必须手动维护
'controllers/controllers',
'services/services',
'directives/directives',
'filters/filters' ],
function(app) {
'use strict';
return app.config( [ '$routeProvider', function($routeProvider) {
$routeProvider.when('/view1', {
templateUrl : 'partials/partial1.html',
controller : 'MyCtrl1'
});
$routeProvider.when('/view2', {
templateUrl : 'partials/partial2.html',
controller : 'MyCtrl2'
});
$routeProvider.otherwise( {
redirectTo : '/view1'
});
} ]);
}
);
然后定义一个app.js文件。这个文件定义了AngularJS应用,并且告诉它去依赖我们所定义的所有控制器、服务、过滤器及指令。
你可以把RequireJS依赖列表看作JavaScript版的阻塞型import语句。也就是说,除非依赖列表中的内容都已经加载完或准备好,否则语句块中的函数不会开始执行。
同时要注意,我们不会单独让RequireJS去加载指令、服务或过滤器,因为这不是当前这个项目的组织方式。对于每个控制器、服务、过滤器及指令,都有一个模块与之对应,因此,只要把这些模块定义成我们所依赖的东西就够了。
app.js
define(['angular',
'angular-route',
'./controllers/index',
'./directives/index',
'./filters/index',
'./services/index'
], function (angular) {
'use strict';
return angular.module('app', [
'controllers',
'directives',
'filters',
'services',
'ngRoute'
]);
});
我们还有一份bootstrap.js文件,它将会等待DOM结构准备好(使用RequireJS的插件domReady),然后告诉AngularJS一切都已就绪,可以开始运行了。
bootstrap.js
//当DOM结构加载完成后,bootstrap.js文件将会命令AngularJS启动起来并继续执行define(['angular', 'domReady', 'app'], function(angular, domReady) {
require(['domReady!'], function (document) {
angular.bootstrap(document, ['app']);
});
});
把启动过程和应用代码分离开还有另一个好处,那就是,为了测试,我们可能会潜在地把mainApp替换成虚拟的代码或者mockApp。例如,如果所依赖的服务器是不可靠的,你可能会创建一个fackApp,用来代替所有$http请求,它会返回一些虚拟的数据来保证开发过程顺利进行。这样一来,你可能只是把fakeBootstrap和fackApp放到了应用中。
index.html
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>AngularJS与RequireJS集成App</title>
<link rel="stylesheet"href="css/app.css">
</head>
<body>
<ul class="menu">
<li><a href="#/view1">view1</a></li>
<li><a href="#/view2">view2</a></li>
</ul>
<div data-ng-view></div>
<div>Angular Require seed app: v<span app-version></span></div>
<script src="lib/requirejs/require.js"data-main="js/main.js"></script>
</body>
</html>
下面来看看js/controllers/controllers.js文件里面的内容,它看起来几乎和js/directives/directives.js、js/filters/filters.js及js/services/services一模一样。
define(['angular'], function (angular) { 'use strict';
return angular.module('controllers', []);
});
我们组织RequireJS依赖关系的方式会保证在Angular所依赖的内容加载并准备好之后,所有的东西才会运行。
js/controllers/、js/directives/、js/filters/及js/services/里面都会定义一个AngularJS模块,并且对于每一个单独的控制器、指令、过滤器及服务,在声明的时候都会添加对应的模块依赖。
js/controllers/index.js
define(['./my-ctrl-1',
'./my-ctrl-2'
], function () {});
js/directives/index.js
define(['./app-version'], function () {});
再进一步看一下控制器和指令的定义:
my-ctrl-1.js
define(['controllers/controllers'], function (controllers) { 'use strict';
controllers.controller('MyCtrl1', [function ($scope) {}]);
});
my-ctrl-2.js
define(['controllers/controllers'], function (controllers) { 'use strict';
controllers.controller('MyCtrl2', [function ($scope) {}]);
});
app-version.js
define(['directives/directives'], function (directives) { 'use strict';
directives.directive('appVersion', ['version', function (version) {
return function (scope, elm) {
elm.text(version);
};
}]);
});
指令本身是非常琐碎的,但是我们还是来仔细看一下正在发生什么事情。RequireJS将会在文件两端添加一些东西,这些东西会说我的app-version.js文件会依赖模块声明文件directives/directives.js。然后这份文件就会使用插入了指令的模块去添加自已的指令声明。你可以把单条或者多条指令放在同一份文件里面,这完全由你自已决定。
其中有一个主要的注意点:如果你有一个控制器,且这个控制器会从一个后台服务中拉取数据(例如RootConroller依赖于UserService,它被注入了UserService),这种情况下,你就必须确保在RequireJS中也定义了服务文件的依赖,示例如下:
define(['controllers/controllers', 'services/services'], function(controllers) { controllers.controller('RootController', ['$scope', 'UserService',
function($scope, UserService) {
//做需要做的事情
};
}]);
});
以上就是整个源码文件夹基本的配置方式。
参考书籍:《用AngularJS开发下一代Web应用》
参考源码:https://github.com/StarterSquad/startersquad.com/tree/master/examples/angularjs-requirejs-1
附件工程源码:
1.原来的AngularJSSeed工程源码AngularJSSeed.rar
2.与RequireJS集成后的工程源码AngularRequireSeed.rar
3.github上的工程源码AngularRequireJSSeed.rar