http://docs.angularjs.org/guide/module
很多程序都有一个入口方法用来引导和初始化程序。Angular的程序没有main方法,而是用“模块”来实现同样的功能。它有以下优点:
我很忙,快上一个"Hello world"的模块瞧瞧?
重点内容需注意:
<html ng-app="myApp">
中对myApp
模块的引用,这句话说明指示用什么模块来初始化你的程序index.html
<!doctype html>
<html ng-app="simpleApp">
<head>
<script src="http://code.angularjs.org/angular-1.0.1.min.js"></script>
<script src="script.js"></script>
</head>
<body>
<div>
{{ 'World' | greet }}
</div>
</body>
</html>
**script.js**
// declare a module
var simpleAppModule = angular.module('simpleApp', []);
// configure the module.
// in this example we will create a greeting filter
simpleAppModule.filter('greet', function() {
return function(name) {
return 'Hello, ' + name + '!';
};
});
#### 推荐的设置
上面的例子很简单,它不适用于大程序。我们推荐你把自己的程序,分成以下几个模块来组织:
service模块,用来声明service directive模块,用来声明directive filter模块,用来声明filter* 一个依赖于以上几个模块的程序级的模块,包含初始化代码
之所以这样是为了方便测试。在测试中,通常忽略初始化代码,因为它们很难测试。分开以后,我们就可以只针对某些功能进行测试,忽略其它。
以上仅仅是建议,请根据你的实际情况进行更改
index.html
<script src="http://code.angularjs.org/angular-1.0.1.min.js"></script>
<script src="script.js"></script>
<div ng-controller="XmplController">
{{ greeting }}!
</div>
script.js
angular.module('xmpl.service', []).
value('greeter', {
salutation: 'Hello',
localize: function(localization) {
this.salutation = localization.salutation;
},
greet: function(name) {
return this.salutation + ' ' + name + '!';
}
}).
value('user', {
load: function(name) {
this.name = name;
}
});
angular.module('xmpl.directive', []);
angular.module('xmpl.filter', []);
angular.module('xmpl', ['xmpl.service', 'xmpl.directive', 'xmpl.filter']).
run(function(greeter, user) {
// This is effectively part of the main method initialization code
greeter.localize({
salutation: 'Bonjour'
});
user.load('World');
})
// A Controller for your app
var XmplController = function($scope, greeter, user) {
$scope.greeting = greeter.greet(user.name);
}
jsfiddle
模块就是在程序初始化阶段的配置和执行操作。在最简单的简单下,只考虑以下两种情况:
配置块 - 在provider的注册与配置阶段执行。只有providers和常量可以被注入到配置块里。这么做是为了防止在services配置好之前,就将它们意外初始化了。
执行块 - 在injector创建好之后执行,用来启动程序。只有实例和常量可以被注入到执行块中。这么做是为了防止在程序运行阶段还在对系统进行配置。
angular.module('myModule', []).
config(function(injectables) { // provider-injector
// This is an example of config block.
// You can have as many of these as you want.
// You can only inject Providers (not instances)
// into the config blocks.
}).
run(function(injectables) { // instance-injector
// This is an example of a run block.
// You can have as many of these as you want.
// You can only inject instances (not Providers)
// int the run blocks
});
对于配置块,angular提供了一些更便于使用的方法,用来代替对上例中config
方法的调用。
angular.module('myModule', []).
value('a', 123).
factory('a', function() { return 123; }).
directive('directiveName', …).
filter('filterName', …);
// is same as
angular.module('myModule', []).
config(function($provide, $compileProvider, $filterProvider) {
$provide.value('a', 123)
$provide.factory('a', function() { return 123; })
$compileProvider.directive('directiveName', ...).
$filterProvider.register('filterName', ...);
});
配置块按它们声明的顺序来执行。唯一的例外是常量声明,它们会提前到配置块的最前部。
执行块是angular中最像main方法的东西。一个执行块就是一些用来启动程序的代码。它在所有的service被配置好,所有的injector创建好之后执行。执行块中经常包含一些难以单元测试的代码,所以它应该被声明在一个孤立的模块中,以便在测试时忽略它。
模块可以声明依赖于其它的模块。被依赖的模块会被先导入并执行(包括配置块和执行块)。每个模块只能导入一次,不管它被多少个模块依赖。
模块仅仅是用来管理$injector
配置的一种方式,与“把脚本导入到VM“中无关。当前已经有一些库专门用来处理脚本的导入,它们可以跟angular一起使用。由于模块在导入阶段什么也不做,所以它们可以以任意顺序导入到VM中,所以可以利用一些库来并行导入,提高页面响应速度。
在最简单的情况下,单元测试是一种在测试中初始化程序的功能子集并触发它们的方式。认识到“对于一个injector每个模块只会被导入一次”很重要。在典型的情况下,一个程序只有一个injector。但是在测试中,每个测试都有它自己的injector,这表明在每个VM上,模块可能被导入多次。以适当的结构组织好的模块可以帮助我们进行测试。
在所有的示例中,我们都假设有以下定义:
angular.module('greetMod', []).
factory('alert', function($window) {
return function(text) {
$window.alert(text);
}
}).
value('salutation', 'Hello').
factory('greet', function(alert, salutation) {
return function(name) {
alert(salutation + ' ' + name + '!');
}
});
写些测试:
describe('myApp', function() {
// load the application relevant modules then load a special
// test module which overrides the $window with mock version,
// so that calling window.alert() will not block the test
// runner with a real alert box. This is an example of overriding
// configuration information in tests.
beforeEach(module('greetMod', function($provide) {
$provide.value('$window', {
alert: jasmine.createSpy('alert')
});
}));
// The inject() will create the injector and inject the greet and
// $window into the tests. The test need not concern itself with
// wiring of the application, only with testing it.
it('should alert on $window', inject(function(greet, $window) {
greet('World');
expect($window.alert).toHaveBeenCalledWith('Hello World!');
}));
// this is another way of overriding configuration in the
// tests using an inline module and inject methods.
it('should alert using the alert service', function() {
var alertSpy = jasmine.createSpy('alert');
module(function($provide) {
$provide.value('alert', alertSpy);
});
inject(function(greet) {
greet('World');
expect(alertSpy).toHaveBeenCalledWith('Hello World!');
});
});
});