Angular9 NgModule API
宏观来讲,NgModule 是组织 Angular 应用的一种方式,它们通过 @NgModule 装饰器中的元数据来实现这一点。 这些元数据可以分成三类:
静态的:编译器配置,用于告诉编译器指令的选择器并通过选择器匹配的方式决定要把该指令应用到模板中的什么位置。它是通过 declarations 数组来配置的。
运行时:通过 providers 数组提供给注入器的配置。
组合/分组:通过 imports 和 exports 数组来把多个 NgModule 放在一起,并让它们可用。
@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列表中。