NgModule API
前提条件
对下列概念有基本的理解:
@
NgModule
的设计意图
宏观来讲,NgModule 是组织 Angular 应用的一种方式,它们通过 @
NgModule
装饰器中的元数据来实现这一点。 这些元数据可以分成三类:
- 静态的:编译器配置,用于告诉编译器指令的选择器并通过选择器匹配的方式决定要把该指令应用到模板中的什么位置。它是通过
declarations
数组来配置的。 - 运行时:通过
providers
数组提供给注入器的配置。 - 组合/分组:通过
imports
和exports
数组来把多个 NgModule 放在一起,并彼此可用。
content_copy@NgModule({ // Static, that is compiler configuration declarations: [], // Configure the selectors entryComponents: [], // Generate the host factory // Runtime, or injector configuration providers: [], // Runtime injector configuration // Composability / Grouping imports: [], // composing NgModules together exports: [] // making NgModules available to other parts of the app})
@
NgModule
元数据
下面是 @
NgModule
元数据中属性的汇总表:
属性 | 说明 |
---|---|
declarations | 属于该模块的可声明对象(组件、指令和管道)的列表。当编译模板时,你需要确定一组选择器,它们将用于触发相应的指令。该模板在 NgModule 环境中编译 —— 模板的组件是在该 NgModule 内部声明的,它会使用如下规则来确定这组选择器:列在 declarations 中的所有指令选择器。从所导入的 NgModule 中导出的那些指令的选择器。组件、指令和管道只能属于一个模块。 如果尝试把同一个类声明在多个模块中,编译器就会报告一个错误。 小心,不要重复声明从其它模块中直接或间接导入的类。 |
providers | 依赖注入提供商的列表。Angular 会使用该模块的注入器注册这些提供商。 如果该模块是启动模块,那就会使用根注入器。当需要注入到任何组件、指令、管道或服务时,这些服务对于本注入器的子注入器都是可用的。惰性加载模块有自己的注入器,它通常是应用的根注入器的子注入器。惰性加载的服务是局限于这个惰性加载模块的注入器中的。 如果惰性加载模块也提供了 UserService,那么在这个模块的上下文中创建的任何组件(比如在路由器导航时),都会获得这个服务的本模块内实例,而不是来自应用的根注入器的实例。其它外部模块中的组件也会使用它们自己的注入器提供的服务实例。要深入了解关于多级注入器及其作用域,参见服务提供商。 |
imports | 要折叠(Folded)进本模块中的其它模块。折叠的意思是从被导入的模块中导出的那些软件资产同样会被声明在这里。特别是,这里列出的模块,其导出的组件、指令或管道,当在组件模板中被引用时,和本模块自己声明的那些是等价的。组件模板可以引用其它组件、指令或管道,不管它们是在本模块中声明的,还是从导入的模块中导出的。 比如,只有当该模块导入了 Angular 的 CommonModule(也可能从BrowserModule中间接导入)时,组件才能使用NgIf和NgFor` 指令。你可以从 CommonModule 中导入很多标准指令,不过也有些常用的指令属于其它模块。 比如,你只有导入了 Angular 的 FormsModule 时才能使用 [(ngModel)]。 |
exports | 可供导入了自己的模块使用的可声明对象(组件、指令、管道类)的列表。导出的可声明对象就是本模块的公共 API。 只有当其它模块导入了本模块,并且本模块导出了 UserComponent 时,其它模块中的组件才能使用本模块中的 UserComponent。默认情况下这些可声明对象都是私有的。 如果本模块没有导出 UserComponent,那么就只有本模块中的组件才能使用 UserComponent。导入某个模块并不会自动重新导出被导入模块的那些导入。 模块 B 不会因为它导入了模块 A,而模块 A 导入了 CommonModule 而能够使用 ngIf。 模块 B 必须自己导入 CommonModule。一个模块可以把另一个模块加入自己的 exports 列表中,这时,另一个模块的所有公共组件、指令和管道都会被导出。重新导出可以让模块被显式传递。 如果模块 A 重新导出了 CommonModule,而模块 B 导入了模块 A,那么模块 B 就可以使用 ngIf 了 —— 即使它自己没有导入 CommonModule。 |
bootstrap | 要自动启动的组件列表。通常,在这个列表中只有一个组件,也就是应用的根组件。Angular 也可以引导多个引导组件,它们每一个都在宿主页面中有自己的位置。启动组件会自动添加到 entryComponents 中。 |
entryComponents | 那些可以动态加载进视图的组件列表。默认情况下,Angular 应用至少有一个入口组件,也就是根组件 AppComponent。 它用作进入该应用的入口点,也就是说你通过引导它来启动本应用。路由组件也是入口组件,因为你需要动态加载它们。 路由器创建它们,并把它们扔到 DOM 中的 <router-outlet> 附近。虽然引导组件和路由组件都是入口组件,不过你不用自己把它们加到模块的 entryComponents 列表中,因为它们会被隐式添加进去。Angular 会自动把模块的 bootstrap 中的组件和路由定义中的组件添加到 entryComponents列表。而那些使用不易察觉的ViewComponentRef.createComponent()的方式进行命令式引导的组件仍然需要添加。动态组件加载在除路由器之外的大多数应用中都不太常见。如果你需要动态加载组件,就必须自己把那些组件添加到 entryComponents 列表中。要了解更多,参见入口组件一章。 |
- 当编译模板时,你需要确定一组选择器,它们将用于触发相应的指令。
- 该模板在 NgModule 环境中编译 —— 模板的组件是在该 NgModule 内部声明的,它会使用如下规则来确定这组选择器:
- 列在
declarations
中的所有指令选择器。 - 从所导入的 NgModule 中导出的那些指令的选择器。
- 列在
组件、指令和管道只能属于一个模块。 如果尝试把同一个类声明在多个模块中,编译器就会报告一个错误。 小心,不要重复声明从其它模块中直接或间接导入的类。providers
依赖注入提供商的列表。
Angular 会使用该模块的注入器注册这些提供商。 如果该模块是启动模块,那就会使用根注入器。
当需要注入到任何组件、指令、管道或服务时,这些服务对于本注入器的子注入器都是可用的。
惰性加载模块有自己的注入器,它通常是应用的根注入器的子注入器。
惰性加载的服务是局限于这个惰性加载模块的注入器中的。 如果惰性加载模块也提供了 UserService
,那么在这个模块的上下文中创建的任何组件(比如在路由器导航时),都会获得这个服务的本模块内实例,而不是来自应用的根注入器的实例。
其它外部模块中的组件也会使用它们自己的注入器提供的服务实例。
要深入了解关于多级注入器及其作用域,参见服务提供商。imports
要折叠(Folded)进本模块中的其它模块。折叠的意思是从被导入的模块中导出的那些软件资产同样会被声明在这里。
特别是,这里列出的模块,其导出的组件、指令或管道,当在组件模板中被引用时,和本模块自己声明的那些是等价的。
组件模板可以引用其它组件、指令或管道,不管它们是在本模块中声明的,还是从导入的模块中导出的。 比如,只有当该模块导入了 Angular 的 CommonModule
(也可能从
BrowserModule中间接导入)时,组件才能使用
NgIf和
NgFor` 指令。
你可以从 CommonModule
中导入很多标准指令,不过也有些常用的指令属于其它模块。 比如,你只有导入了 Angular 的 FormsModule
时才能使用 [(
ngModel
)]
。exports
可供导入了自己的模块使用的可声明对象(组件、指令、管道类)的列表。
导出的可声明对象就是本模块的公共 API。 只有当其它模块导入了本模块,并且本模块导出了 UserComponent
时,其它模块中的组件才能使用本模块中的 UserComponent
。
默认情况下这些可声明对象都是私有的。 如果本模块没有导出 UserComponent
,那么就只有本模块中的组件才能使用 UserComponent
。
导入某个模块并不会自动重新导出被导入模块的那些导入。 模块 B 不会因为它导入了模块 A,而模块 A 导入了 CommonModule
而能够使用 ngIf
。 模块 B 必须自己导入 CommonModule
。
一个模块可以把另一个模块加入自己的 exports
列表中,这时,另一个模块的所有公共组件、指令和管道都会被导出。
重新导出可以让模块被显式传递。 如果模块 A 重新导出了 CommonModule
,而模块 B 导入了模块 A,那么模块 B 就可以使用 ngIf
了 —— 即使它自己没有导入 CommonModule
。bootstrap
要自动启动的组件列表。
通常,在这个列表中只有一个组件,也就是应用的根组件。
Angular 也可以引导多个引导组件,它们每一个都在宿主页面中有自己的位置。
启动组件会自动添加到 entryComponents
中。entryComponents
那些可以动态加载进视图的组件列表。
默认情况下,Angular 应用至少有一个入口组件,也就是根组件 AppComponent
。 它用作进入该应用的入口点,也就是说你通过引导它来启动本应用。
路由组件也是入口组件,因为你需要动态加载它们。 路由器创建它们,并把它们扔到 DOM 中的 <
router-outlet
>
附近。
虽然引导组件和路由组件都是入口组件,不过你不用自己把它们加到模块的 entryComponents
列表中,因为它们会被隐式添加进去。
Angular 会自动把模块的 bootstrap
中的组件和路由定义中的组件添加到 entryComponents
列表。
而那些使用不易察觉的ViewComponentRef.createComponent()
的方式进行命令式引导的组件仍然需要添加。
动态组件加载在除路由器之外的大多数应用中都不太常见。如果你需要动态加载组件,就必须自己把那些组件添加到 entryComponents
列表中。
要了解更多,参见入口组件一章。
本文档系腾讯云开发者社区成员共同维护,如有问题请联系 cloudcommunity@tencent.com