特性模块的分类

特性模块的分类

前提条件

对下列概念有基本的理解:

下面是特性模块的五个常用分类,包括五组:

  • 领域特性模块。

虽然下面的指南中描述了每种类型的使用及其典型特征,但在实际的应用中,你还可能看到它们的混合体。

特性模块指导原则
领域领域特性模块用来给用户提供应用程序领域中特有的用户体验,比如编辑客户信息或下订单等。它们通常会有一个顶级组件来充当该特性的根组件,并且通常是私有的。用来支持它的各级子组件。领域特性模块大部分由 declarations 组成,只有顶级组件会被导出。领域特性模块很少会有服务提供商。如果有,那么这些服务的生命周期必须和该模块的生命周期完全相同。领域特性模块通常会由更高一级的特性模块导出且只导出一次。对于缺少路由的小型应用,它们可能只会被根模块 AppModule 导入一次。
路由带路由的特性模块是一种特殊的领域特性模块,但它的顶层组件会作为路由导航时的目标组件。根据这个定义,所有惰性加载的模块都是路由特性模块。带路由的特性模块不会导出任何东西,因为它们的组件永远不会出现在外部组件的模板中。惰性加载的路由特性模块不应该被任何模块导入。如果那样做就会导致它被立即加载,破坏了惰性加载的设计用途。 也就是说你应该永远不会看到它们在 AppModule 的 imports 中被引用。 立即加载的路由特性模块必须被其它模块导入,以便编译器能了解它所包含的组件。路由特性模块很少会有服务提供商,原因参见惰性加载的特性模块中的解释。如果那样做,那么它所提供的服务的生命周期必须与该模块的生命周期完全相同。不要在路由特性模块或被路由特性模块所导入的模块中提供全应用级的单例服务。
路由路由模块为其它模块提供路由配置,并且把路由这个关注点从它的配套模块中分离出来。路由模块通常会做这些:定义路由。把路由配置添加到该模块的 imports 中。把路由守卫和解析器的服务提供商添加到该模块的 providers 中。路由模块应该与其配套模块同名,但是加上“Routing”后缀。比如,foo.module.ts 中的 FooModule 就有一个位于 foo-routing.module.ts 文件中的 FooRoutingModule 路由模块。 如果其配套模块是根模块 AppModule,AppRoutingModule 就要使用 RouterModule.forRoot(routes) 来把路由器配置添加到它的 imports 中。 所有其它路由模块都是子模块,要使用 RouterModule.forChild(routes)。按照惯例,路由模块会重新导出这个 RouterModule,以便其配套模块中的组件可以访问路由器指令,比如 RouterLink 和 RouterOutlet。路由模块没有自己的可声明对象。组件、指令和管道都是特性模块的职责,而不是路由模块的。路由模块只应该被它的配套模块导入。
服务服务模块提供了一些工具服务,比如数据访问和消息。理论上,它们应该是完全由服务提供商组成的,不应该有可声明对象。Angular 的 HttpClientModule 就是一个服务模块的好例子。根模块 AppModule 是唯一的可以导入服务模块的模块。
窗口部件窗口部件模块为外部模块提供组件、指令和管道。很多第三方 UI 组件库都是窗口部件模块。窗口部件模块应该完全由可声明对象组成,它们中的大部分都应该被导出。窗口部件模块很少会有服务提供商。如果任何模块的组件模板中需要用到这些窗口部件,就请导入相应的窗口部件模块。

  • 定义路由。

路由模块只应该被它的配套模块导入。服务服务模块提供了一些工具服务,比如数据访问和消息。理论上,它们应该是完全由服务提供商组成的,不应该有可声明对象。Angular 的 HttpClientModule 就是一个服务模块的好例子。 根模块 AppModule 是唯一的可以导入服务模块的模块。窗口部件窗口部件模块为外部模块提供组件、指令和管道。很多第三方 UI 组件库都是窗口部件模块。 窗口部件模块应该完全由可声明对象组成,它们中的大部分都应该被导出。 窗口部件模块很少会有服务提供商。 如果任何模块的组件模板中需要用到这些窗口部件,就请导入相应的窗口部件模块。

下表中汇总了各种特性模块类型的关键特征。

特性模块声明 declarations提供商 providers导出什么被谁导入
领域罕见顶级组件特性模块,AppModule
路由罕见
路由是(守卫)RouterModule特性(供路由使用)
服务AppModule
窗口部件罕见特性

关于 NgModule 的更多知识

你可能还对下列内容感兴趣: