AngularJS能够很好地与RequireJS(​​http://www.requirejs.org/​​)配合使用,这使得我们可以同时拥有两种组件的优点。下面通过配置AngularJS官方的AngularSeed实例,来看一下AngularJS与RequireJS集成组织项目的方式。

        项目结构: 

AngularJS与RequireJS集成_angular.js

                                                                                             首先,我们需要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