AngularJS与RequireJS集成

Chasingsun 2014-09-07

        RequireJS允许你定义和管理JS文件之间的依赖关系,把这些工作变成了一个简单的构建过程。利用这些异步加载管理工具,可以保证在代码执行之前所有依赖的东西就已经被加载好了——专注于开发实际的应用功能从来没有如此简单过。

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

        项目结构:
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

相关推荐