特性模块

14次阅读

共计 3334 个字符,预计需要花费 9 分钟才能阅读完成。

本周边写项目边进一步学习 angular,主要侧重看了模块这一部分,之前没怎么看懂,这里写下自己的学习理解。

特性模块概念

特性模块提供了聚焦于特定应用需求的一组功能,比如用户工作流、路由或表单。虽然你也可以用根模块做完所有事情,不过特性模块可以帮助你把应用划分成一些聚焦的功能区。特性模块通过它提供的服务以及共享出的组件、指令和管道来与根模块和其它模块合作。

特性模块其实就是把一个大的系统分成一份份的模块,分别专注与服务, 路由,共享组件,还有特定的领域这些方面,把他们组合在一起就足以构成一个功能完善的 webapp,之所以把它划分,是因为能够让我们专注与各个领域详细开发,方便维护。

特性模块的分类

特性模块分为五个部分:

  • 领域特性模块。
  • 带路由的特性模块。
  • 路由模块。
  • 服务特性模块
  • 可视部件特性模块。

领域特性模块

领域特性模块就是用来提供应用程序中某个领域独特的用户体验,就好比教师模块专注与教师,学院模块专注与管理学院. 通常它们会有跟多 declarations 的组件, 但应该只有一个顶级组件来充当根组件并把他导出,供外部使用。
比如我现在创建一个 TeacherModule, 声明如下:

@NgModule({declarations: [TeacherListComponent, TeacherSearchComponent, TeacherIndexComponent],
  imports: [CommonModule]
})
export class TeacherModule {}

这个模块包含 teacher 列表组件用来展示教师数据, 还有一个 TeacherSearch 组件来搜索教师, 用 index 组件来做根组件, 在 teacherIndex 组件中使用 teacherList 和 teacherSearch 组件:

<p>
  teacher-index works!
  <app-teacher-search></app-teacher-search>
  <app-teacher-list></app-teacher-list>
</p>

再将 teacherIndex 组件导出,作为 teacherModule 的根组件:

@NgModule({declarations: [TeacherListComponent, TeacherSearchComponent, TeacherIndexComponent],
  imports: [CommonModule],
  exports: [TeacherIndexComponent]
})
export class TeacherModule {}

在 AppModule 导入我们的领域模块 TeacherModule, 并在 AppComponent 里使用 teacher-index 组件:

@NgModule({
  declarations: [
    AppComponent,
    MainComponent
  ],
  imports: [
    BrowserModule,
    AppRoutingModule,
    HttpClientModule,
    TeacherModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule {
}

<app-teacher-index></app-teacher-index>

效果如图:

我们只暴露了一个 teacherIndex 组件给根模块使用, 关于教师的展示,搜索组件都是在我们自己的 teacherModule 中定义的, 也就是 TeacherModule 专注于 Teacher 领域,而根模块并不需要知道怎么实现的,这就把应用划分为了一个个的领域模块了.
特性模块不应该有自己的服务提供商,除非需要,服务提供商应该注册在根模块上.

带路由的特性模块

带路由的特性模块是一种特殊的领域特性模块,但它的顶层组件会作为路由导航时的目标组件。所有的惰性加载模块都是带路由的特性模块.
在上面那个例子中,我们的模块直接导入了 AppModule 中,这个就是急性加载了,我们可以通过配置模块的路由实现惰性加载。
我们先配置 AppRoutingModule 的路由:

const routes: Routes = [
  {
    path: 'teacher',
    loadChildren: './teacher/teacher.module#TeacherModule'
  }
];

我们配置这样一条路由,当路由为 teacher 路径时,去加载./teacher/teacher.module 文件的 TeacherModule 模块, 因此当路径为 teacher 时 angular 就会将我们的 TeacherModule 加载进来了, 为此,我们不需要导入 TeacherModule, 并且 TeacherModue 也不需要导出任何的根组件:

// AppModule 中删除导入的 TeacherModule
@NgModule({
  declarations: [
    AppComponent,
    MainComponent
  ],
  imports: [
    BrowserModule,
    AppRoutingModule,
    HttpClientModule,
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule {
}
//TeacehrModule 中取消导出 index 组件 惰性加载模块并不需要导出组件
@NgModule({declarations: [TeacherListComponent, TeacherSearchComponent, TeacherIndexComponent],
  imports: [CommonModule],
})
export class TeacherModule {
}
//AppComponent 中将 <app-teacher-index> 改成路由出口
<router-outlet></router-outlet>

之后我们在配置 TeacherModule 的路由:

const routes: Routes = [
  {
    path: '',
    component: TeacherIndexComponent
  }
];


@NgModule({declarations: [],
  imports: [RouterModule.forChild(routes)
  ],
  exports: [RouterModule]
})
export class TeacherRoutingModule {}

注意,这里使用 RouterModule.forChild(),使 TeacherModule 不覆盖根模块的路由服务.
在 TeacherModule 中导入路由配置:

const routes: Routes = [
  {
    path: '',
    component: TeacherIndexComponent
  }
];


@NgModule({declarations: [],
  imports: [RouterModule.forChild(routes)
  ],
  exports: [RouterModule]
})
export class TeacherRoutingModule {}

这样,当路由为 teacher 的时候显示的内容就和之前的一样,区别在于我们并没有在根模块中导入 TeacherModule, 教师模块是在路由为 teacher 时才被导入的 AppModule 当中,完成了惰性加载.

路由模块

路由模块为其它模块提供路由配置,并且把路由这个关注点从它的配套模块中分离出来. 如上已经展示,它包含的功能有:

  • 定义路由
  • 把路由配置添加到该模块的 imports 中
  • 把路由守卫和解析器的服务提供商添加到该模块的 providers 中

服务模块

服务模块提供了一些工具服务,比如数据访问和消息。理论上,它们应该是完全由服务提供商组成的,不应该有可声明对象, 通常服务都应该注册在根模块,要是建立服务模块的话,应该只由根模块导入.

窗口部件模块

窗口部件模块一般提供共享的组件、指令和管道。很多第三方 UI 组件库都是窗口部件模块. 我们要想进行组件的共享,都应该能将它独立出来放在窗口部件模块,而不依赖与某个特性领域模块。
窗口组件模块不应该有服务提供商,并且都应导出大部分可声明对象 (declarations);

总结

附上官网的关键特征图:

官网地址

正文完
 0