Angular 学习笔记 (十) - Modules和动态Component

一. Angular的Module

模块Module是组织应用和使用外部库扩展应用的最佳途径。

Angular 自己的库都是 NgModule,比如 FormsModuleHttpClientModule 和 RouterModule。 很多第三方库也是 NgModule,比如 Material Design、 Ionic 和 AngularFire2

NgModule 把组件、指令和管道打包成内聚的功能块,每个模块聚焦于一个特性区域、业务领域、工作流或通用工具。

模块还可以把服务加到应用中。 这些服务可能是内部开发的(比如你自己写的),或者来自外部的(比如 Angular 的路由和 HTTP 客户端)。

模块可以在应用启动时急性加载,也可以由路由器进行异步的惰性加载。

NgModule 的元数据会做这些:

  • 声明某些组件、指令和管道属于这个模块。

  • 公开其中的部分组件、指令和管道,以便其它模块中的组件模板中可以使用它们。

  • 导入其它带有组件、指令和管道的模块,这些模块中的元件都是本模块所需的。

  • 提供一些供应用中的其它组件使用的服务。

每个 Angular 应用都至少有一个模块,也就是根模块。 你可以引导那个模块,以启动该应用。

对于那些只有少量组件的简单应用,根模块就是你所需的一切。 随着应用的成长,你要把这个根模块重构成一些特性模块,它们代表一组密切相关的功能集。 然后你再把这些模块导入到根模块中。

当输入一个命令生成一个新的模块:

ng generate module heroes

之后会自动生成一个heroes.module.ts文件

import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
@NgModule({
  declarations: [],
  imports: [
    CommonModule
  ]
})
export class HeroesModule { }

引入NgModule:

  • Declarations:

注册的组件、指令和管道模块。

Declarations具有唯一性,当Component在一个Module中加入Declaration,就不能出现在其它模块的Declaration中

  • imports:

包含此模块要使用的声明的其他模块。Angular CLI会在这个属性中自动为我们定义CommonModule。一个模块是否总是在Angular应用中使用,因为它包含了所有的我们通常喜欢使用的内置指令和管道。

Imports不具有唯一性,但代码中要避免循环引用。(A import B, B import A)

  • exports:

Angular构件,在声明中定义并可供其他模块使用。这是模块的公共API。它定义了什么公开访问或不公开访问。其他没有显式导出的东西都是被认为是私有的或模块内部的。

  • providers:

由模块提供且可访问的服务从应用程序的任何模块,用于依赖注入

  • bootstrap:

应用程序的主要组件,当应用程序启动。此属性只在主应用程序中设置一次一个AppModule模块,通常是AppComponent。

通常情况下,你不应该更改它,除非有特别的理由。

 

二. Lazy-load 

默认情况下,NgModule 都是急性加载 (Eager-load) 的,也就是说它会在应用加载时尽快加载,所有模块都是如此,无论是否立即要用。对于带有很多Routes的大型应用,考虑使用惰性加载 —— 一种按需加载 NgModule 的模式。

惰性加载可以减小初始包的尺寸,从而减少加载时间。

要使用lazy-load,定义Route如下:

1 const routes: Routes = [
2   {
3     path: 'items',
4     loadChildren: './items/items.module#ItemComponent'
5   }
6 ];

如果使用最新的Typescript标准,代码还可以这样写:

1 const routes: Routes = [
2   {
3     path: 'items',
4     loadChildren: () => import('./items/items.module').then(m => m.ItemsModule)
5   }
6 ];

这需要ts达到最新es标准,在tsconfig.ts修改:

{
  "compileOnSave": false,
  "compilerOptions": {
    "baseUrl": "./",
    "outDir": "./dist/out-tsc",
    "sourceMap": true,
    "declaration": false,
    ”module“: esnext,
    "moduleResolution": "node",
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true,
    "target": "es5",
    "typeRoots": [
      "node_modules/@types"
    ],
    "lib": [
      "es2017",
      "dom"
    ]
  }
}

 

三. 动态Component

Dynamic component用于Component不事先在template中实现的情况,可以用ComponentFactory产生一个Component。

(这种case也可以被其它技术路线替代,比如NgIf)

示例:

需要动态加载这样一个简单的Component:弹出一个警告框,message:string作为输入,提供一个close按钮。

 1 import { Component, EventEmitter, Input, Output } from "@angular/core";
 2 
 3 @Component({
 4   selector: "app-alert",
 5   templateUrl: "./alert.component.html",
 6   styleUrls: ['./alert.component.css']
 7 })
 8 export class AlertComponent {
 9 
10     @Input() message:string;
11 
12     @Output() close = new EventEmitter<void>();    
13 
14     onClose() {
15         this.close.emit();
16     }
17 
18 }

在下函数中实现动态创建:

 1   private showErrorAlert(message: string) {
 2     const alertComponentFactory = this.componentFactoryResolver.resolveComponentFactory(
 3       AlertComponent
 4     );
 5     const hostViewContainerRef = this.alertHost.viewContainerRef;
 6     hostViewContainerRef.clear();
 7 
 8     const componentRef = hostViewContainerRef.createComponent(alertComponentFactory);
 9 
10     componentRef.instance.message = message;
11     this.closeSub = componentRef.instance.close.subscribe(() => {
12       this.closeSub.unsubscribe();
13       hostViewContainerRef.clear();
14     });
15   }

其中 alertHost 是主视图中的html template元素

Angular11以下的版本在app.module.ts中,使用这个模块需要:

@NgModule({
  entryComponents: [AlertComponent]   //Expire in Angular 11
})

 

posted @ 2021-04-19 17:20  Asp1rant  阅读(329)  评论(0编辑  收藏  举报