目录
- What is a Module?:什么是模块?
- Why?:为什么会有模块的概念呢?
- The Basics:基础
- Recommended Setup:推荐的设置
- Module Loading:模块加载
- Dependencies and Order of execution:依赖性和执行顺序
- Registration in the config block:在配置块中的注册
- Run Blocks:运行块
- Asynchronous Loading:异步加载
- Creation versus Retrieval:创作与检索
- Unit Testing:单元测试
What is a Module?
You can think of a module as a container for the different parts of your app – controllers, services, filters, directives, etc.
您可以将模块视为应用程序不同部分的容器 - 控制器,服务,过滤器,指令等。
Why?
Most applications have a main method that instantiates and wires together the different parts of the application.
大多数应用程序都有一个主要方法,可以实例化并将应用程序的不同部分连接在一起。
AngularJS apps don't have a main method. Instead modules declaratively specify how an application should be bootstrapped. There are several advantages to this approach:
AngularJS应用程序没有主要方法。相反,模块以声明方式指定应如何引导应用程序。这种方法有几个优点:
- The declarative process is easier to understand.
- 声明性过程更容易理解。
- You can package code as reusable modules.
- 您可以将代码打包为可重用模块。
- The modules can be loaded in any order (or even in parallel) because modules delay execution.
- 模块可以按任何顺序(甚至并行)加载,因为模块会延迟执行。
- Unit tests only have to load relevant modules, which keeps them fast.
- 单元测试只需要加载相关模块,这样可以使它们保持快速。
- End-to-end tests can use modules to override configuration.
- 端到端测试可以使用模块来覆盖配置。
The Basics
I'm in a hurry. How do I get a Hello World module working?
我很急。如何让Hello World模块正常工作?
<!--index.html-->
<div ng-app="myApp">
<div>
{{ 'World' | greet }}
</div>
</div>
<!--script.js-->
// declare a module
var myAppModule = angular.module('myApp', []);
// configure the module.
// in this example we will create a greeting filter
myAppModule.filter('greet', function() {
return function(name) {
return 'Hello, ' + name + '!';
};
});
Important things to notice:
需要注意的重要事项:
- The Module API
- 该模块 API
- The reference to myApp module in . This is what bootstraps the app using your module.
- 对myApp模块的引用。这是使用您的模块引导应用程序的内容。
- The empty array in angular.module('myApp', []). This array is the list of modules myApp depends on.
- angular.module('myApp', [])中的空数组。这个数组是依赖于模块的列表。
声明模块
- 使用angular.module()方法来声明模块
- 这个方法接受两个参数。第一个是模块的名称,第二个是依赖列表,也就是可以被注入到模块中的对象列表。angular.module('myApp',[]);
Recommended Setup
While the example above is simple, it will not scale to large applications. Instead we recommend that you break your application to multiple modules like this:
虽然上面的示例很简单,但它不能扩展到大型应用程序。相反,我们建议您将应用程序分解为多个模块,如下所示:
- A module for each feature
- 每个功能模块
- A module for each reusable component (especially directives and filters)
- 每个可重用组件的模块(特别是指令和过滤器)
- And an application level module which depends on the above modules and contains any initialization code.
- 还有一个应用程序级模块,它依赖于上面的模块并包含任何初始化代码。
You can find a community style guide to help yourself when application grows.
您可以找到社区,以便在应用程序更新时帮助自己。
The above is a suggestion. Tailor it to your needs.
以上是一个建议。根据您的需求量身定制。
Module Loading
A module is a collection of providers, services, directives etc., and optionally config and run blocks which get applied to the application during the bootstrap process.
一个模块是供应商,服务,指令等的集合,以及其中获得在引导过程中施加到该应用程序的配置块和运行块。
The module API describes all the available methods and how they can be used.
该模块API描述了所有可用的方法,以及如何使用。
See Using Dependency Injection to find out which dependencies can be injected in each method.
请参阅使用依赖关系注入以找出可以在每个方法中注入哪些依赖关系。
Dependencies and Order of execution
Modules can list other modules as their dependencies. Depending on a module implies that the required module will be loaded before the requiring module is loaded.
模块可以列出其他模块作为其依赖项。根据模块的不同,暗示在加载需求模块之前将加载所需的模块。
In a single module the order of execution is as follows:
在单个模块中,执行顺序如下:
-
provider functions are executed, so they and the services they define can be made available to the $injector.
- 执行提供程序函数,因此它们和它们定义的服务可以用于$ injector。
-
After that, the configuration blocks (config functions) are executed. This means the configuration blocks of the required modules execute before the configuration blocks of any requiring module.
- 之后,执行配置块(配置功能)。这意味着所需模块的配置块在任何需求模块的配置块之前执行。
This continues until all module dependencies has been resolved.
这一直持续到所有模块依赖关系都已解决。
Then, the run blocks that have been collected from each module are executed in order of requirement.
然后,按照要求的顺序执行从每个模块收集的运行块。
Note: each module is only loaded once, even if multiple other modules require it. Note: the factory function for "values" and "services" is called lazily when the value/service is injected for the first time.
注意:即使多个其他模块需要,每个模块也只加载一次。注意:首次注入值/服务时,“值”和“服务”的工厂函数会被称为懒惰。
Registration in the config block
While it is recommended to register injectables directly with the module API, it is also possible to register services, directives etc. by injecting $provide or the individual service providers into the config function:
虽然建议直接使用模块API注册注入,但也可以通过将$ provide或各个服务提供者注入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', ...);
});
Run Blocks
Run blocks are the closest thing in AngularJS to the main method. A run block is the code which needs to run to kickstart the application. It is executed after all of the services have been configured and the injector has been created. Run blocks typically contain code which is hard to unit-test, and for this reason should be declared in isolated modules, so that they can be ignored in the unit-tests.
运行块是AngularJS中与main方法最接近的东西。运行块是需要运行以启动应用程序的代码。在配置完所有服务并创建注入器后执行。运行块通常包含难以进行单元测试的代码,因此应在隔离模块中声明,以便在单元测试中忽略它们。
Asynchronous Loading
Modules are a way of managing $injector configuration, and have nothing to do with loading of scripts into a VM. There are existing projects which deal with script loading, which may be used with AngularJS. Because modules do nothing at load time they can be loaded into the VM in any order and thus script loaders can take advantage of this property and parallelize the loading process.
模块是管理$ injector配置的一种方式,与将脚本加载到VM无关。现有的项目处理脚本加载,可以与AngularJS一起使用。由于模块在加载时不执行任何操作,因此可以按任何顺序将其加载到VM中,因此脚本加载器可以利用此属性并并行化加载过程。
Creation versus Retrieval
Beware that using angular.module('myModule', []) will create the module myModule and overwrite any existing module named myModule. Use angular.module('myModule') to retrieve an existing module.
请注意,使用将创建模块并覆盖任何已命名的模块。使用检索现有模块。angular.module('myModule', [])myModulemyModuleangular.module('myModule')
var myModule = angular.module('myModule', []);
// add some directives and services
myModule.service('myService', ...);
myModule.directive('myDirective', ...);
// overwrites both myService and myDirective by creating a new module
var myModule = angular.module('myModule', []);
// throws an error because myOtherModule has yet to be defined
var myModule = angular.module('myOtherModule');
Unit Testing
A unit test is a way of instantiating a subset of an application to apply stimulus to it. Small, structured modules help keep unit tests concise and focused.
单元测试是一种实例化应用程序子集以对其应用激励的方法。小型结构化模块有助于保持单元测试的简洁性和重点。
Each module can only be loaded once per injector. Usually an AngularJS app has only one injector and modules are only loaded once. Each test has its own injector and modules are loaded multiple times.
每个模块只能在每个进样器上加载一次。通常,AngularJS应用程序只有一个注入器,模块只加载一次。每个测试都有自己的注入器,模块多次加载。
In all of these examples we are going to assume this module definition:
在所有这些示例中,我们将假设此模块定义:
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 application module (`greetMod`) then load a special
// test module which overrides `$window` with a mock version,
// so that calling `window.alert()` will not block the test
// runner with a real alert box.
beforeEach(module('greetMod', function($provide) {
$provide.value('$window', {
alert: jasmine.createSpy('alert')
});
}));
// inject() will create the injector and inject the `greet` and
// `$window` into the tests.
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 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!');
});
});
});