Angular ViewContainerRef 怎么用?

文章导读
上一个 测验 下一个 动态创建和渲染组件的第二种方式是使用 ViewContainerRef。其他组件或指令使用它来获取对应于它们在 DOM 中位置的视图容器的引用。通过这种方式,ViewContainerRef 有助于在该特定位置动态创建和插入组件。
📋 目录
  1. 示例 - ViewContainerRef 的使用
A A

Angular - 使用 ViewContainerRef



上一个
测验
下一个

动态创建和渲染组件的第二种方式是使用 ViewContainerRef。其他组件或指令使用它来获取对应于它们在 DOM 中位置的视图容器的引用。通过这种方式,ViewContainerRef 有助于在该特定位置动态创建和插入组件。

示例 - ViewContainerRef 的使用

让我们创建一个实时应用程序,以两种不同的格式(table 和 gallery)显示一组员工。我们将创建两个 component,一个以 table 格式显示员工,另一个以 gallery 格式显示。然后我们将创建一个 host component,它将动态加载 table based component 或 gallery based component。

步骤 1: 创建一个 interface,用于在多个动态 component 中保存公共数据

$ ng generate interface DynData
CREATE src/app/dyn-data.ts (29 bytes)

步骤 2: 创建一个动态 component,DynList。该 component 的目的是以 gallery 方式列出员工。

$ ng generate component DynList
CREATE src/app/dyn-list/dyn-list.css (0 bytes)
CREATE src/app/dyn-list/dyn-list.html (23 bytes)
CREATE src/app/dyn-list/dyn-list.spec.ts (567 bytes)
CREATE src/app/dyn-list/dyn-list.ts (209 bytes)

步骤 3: 创建一个动态 component,DynTable。该 component 的目的是以 tabular 格式列出员工。

$ ng generate component DynTable
CREATE src/app/dyn-table/dyn-table.css (0 bytes)
CREATE src/app/dyn-table/dyn-table.html (24 bytes)
CREATE src/app/dyn-table/dyn-table.spec.ts (574 bytes)
CREATE src/app/dyn-table/dyn-table.ts (213 bytes)

步骤 4: 创建一个 host component,DynHost。该 component 的目的是根据配置托管其中一个 component,即 DynList 或 DynTable。

$ ng generate component DynHost
CREATE src/app/dyn-host/dyn-host.css (0 bytes)
CREATE src/app/dyn-host/dyn-host.html (23 bytes)
CREATE src/app/dyn-host/dyn-host.spec.ts (567 bytes)
CREATE src/app/dyn-host/dyn-host.ts (209 bytes)

步骤 5: 接下来,打开 interface DynData 并添加一个数组属性 data

DynData.ts

export interface DynData {
   data : any[]
}

步骤 6: 接下来,打开 DynList component 并实现 DynData interface。

DynList.ts

import { Component } from '@angular/core';
import { DynData } from '../dyn-data';

@Component({
   selector: 'app-dyn-list',
   imports: [],
   templateUrl: './dyn-list.html',
   styleUrl: './dyn-list.css',
})
export class DynList implements DynData {
   data: any[] = []
}

这里,

  • 导入了 DynData interface 并在 class 定义中实现它

  • 按照 DynData interface 规范包含了 data 属性

步骤 7: 接下来,打开 component 的 template 并将数据渲染为 item 列表

dyn-list.html

<div class="gallery">
    @for (item of data; track $index) {
   <div class="card">
      <div class="container">
         <h4><b>{{ item.name }}</b></h4>
         <p>{{ item.role }}</p>
      </div>
   </div>
   }
</div>

这里,

  • data 保存具有 name 和 role 两个属性的员工列表

  • 使用 @for 将员工显示为 card 列表

步骤 8: 接下来,打开 component 的 styles 并添加如下所示的必要 CSS −

dyn-list.css

.gallery {
   display: flex;
   flex-wrap: wrap;
   justify-content: left;
   gap: 10px;
}

.card {
   flex-basis: 200px;
   box-shadow: 0 4px 8px 0 rgba(0,0,0,0.2);
}

.card:hover {
   box-shadow: 0 8px 16px 0 rgba(0,0,0,0.2);
}

.container {
   padding: 2px 16px;
   max-width: 200px;
}

这里,我们使用了 CSS 的 flex 特性来以 gallery 格式显示员工

步骤 9: 接下来,打开 DynTable component 并实现 DynData interface。

DynTable.ts

import { Component } from '@angular/core';
import { DynData } from '../dyn-data';

@Component({
   selector: 'app-dyn-table',
   imports: [],
   templateUrl: './dyn-table.html',
   styleUrl: './dyn-table.css',
})
export class DynTable implements DynData {
   data: any[] = []
}

这里,

  • 导入了 DynData interface 并在 class 定义中实现它

  • 按照 DynData interface 规范包含了 data 属性

步骤 10: 接下来,打开 component 的 template 并将数据渲染为 item 列表

Dyn-Table.html

<table class="employees">
   <thead>
      <tr>
         <th>Name</th>
         <th>Role</th>
      </tr>
   </thead>
   <tbody>
    @for (item of data; track $index) {
      <tr>
         <td>{{ item.name }}</td>
         <td>{{ item.role }}</td>
      </tr>
    }
   </tbody>
</table>

这里,

  • data 保存具有 name 和 role 两个属性的员工列表

  • 使用 @for 将员工渲染为 html table 中的行

步骤 11: 接下来,打开 component 的 styles 并添加如下所示的必要 CSS −

.employees {
   border-collapse: collapse;
   width: 400px;
}

.employees td, .employees th {
   padding: 8px;
}

.employees tbody tr:nth-child(even){background-color: #f2f2f2;}

.employees tbody tr:hover {background-color: #ddd;}

.employees thead th {
   padding-top: 12px;
   padding-bottom: 12px;
   text-align: left;
   background-color: brown;
   color: white;
}

步骤 12: 接下来,打开 DynHost component 的 template 并包含如下所示的 ng-container −

<ng-container #container></ng-container>

这里,我们展示了 ng-container 的用法。

步骤 13: 接下来,打开 DynHostComponent 并导入必要的 classes

import { AfterViewInit, Component, Input, ViewChild, ViewContainerRef } from '@angular/core';

步骤 14: 接下来,导入 interface、list component、table component 和 directive

import { DynData } from '../dyn-data';
import { DynList } from '../dyn-list/dyn-list';
import { DynTable } from '../dyn-table/dyn-table';

步骤 15: 在 class 声明中实现 AfterViewInit life cycle hook

export class DynHost implements AfterViewInit {
}

步骤 16: 声明一个 input property,用于从用户获取 format 信息(table / list)。

@Input() format: string = 'list'

步骤 17: 声明一个 property,data 并设置示例数据

private data = [
   {
      'name': 'John',
      'role': "Manager"
   },
   {
      'name': 'Peter',
      'role': "Marketing Intern"
   },
   {
      'name': 'Mary',
      'role': "Technical Intern"
   },
   {
      'name': 'Jack',
      'role': "Sales Manager"
   },
   {
      'name': 'Jessica',
      'role': "Delivery Head"
   },
]

步骤 18: 使用 @ViewChild 从 template 中获取 ng-container view component

@ViewChild('container', { read: ViewContainerRef }) container!: ViewContainerRef;

步骤 19: 在 ngAfterViewInit life cycle hook 中实现动态创建 component 并加载到适当位置的实际逻辑

ngAfterViewInit() {
      
   if(this.format == 'table') {
      const compRef = this.container.createComponent<DynData>(DynTable);
      compRef.instance.data = this.data;
   } else {
      const compRef = this.container.createComponent<DynData>(DynList);
      compRef.instance.data = this.data;
   }
}

步骤 20: host component 的完整代码如下,

import { AfterViewInit, Component, Input, OnInit, ViewChild, ViewContainerRef } from '@angular/core';

import { DynData } from '../dyn-data';
import { DynList } from '../dyn-list/dyn-list';
import { DynTable } from '../dyn-table/dyn-table';

@Component({
   selector: 'app-dyn-host',
   templateUrl: './dyn-host.html',
   styleUrls: ['./dyn-host.css']
})
export class DynHost implements AfterViewInit {
   @Input() format: string = 'table'
   @ViewChild('container', { read: ViewContainerRef }) container!: ViewContainerRef;
   
   private data = [
   {
      'name': 'John',
      'role': "Manager"
   },
   {
      'name': 'Peter',
      'role': "Marketing Intern"
   },
   {
      'name': 'Mary',
      'role': "Technical Intern"
   },
   {
      'name': 'Jack',
      'role': "Sales Manager"
   },
   {
      'name': 'Jessica',
      'role': "Delivery Head"
   },
  ]
   
   ngAfterViewInit() {
      
      if(this.format == 'table') {
         const compRef = this.container.createComponent<DynData>(DynTable);
         compRef.instance.data = this.data;
      } else {
         const compRef = this.container.createComponent<DynData>(DynList);
         compRef.instance.data = this.data;
      }
   }
}

步骤 21: 接下来,打开 app component 的 template 并包含 host component。

app.html

<app-dyn-host format="table" />

这里,我们指示 host component 以 tabular 格式渲染员工数据。host component 将动态创建 DynTableComponent 并注入到 host component template 中。

步骤 22: 接下来,运行应用程序,你将看到员工数据以 tabular 格式显示,如下所示 −

employee data

步骤 23: 接下来,打开 app component 的 template 并将 format 更改为 gallery。

<app-dyn-host format="gallery" />

这里,我们指示 host component 以 gallery 格式渲染员工数据。host component 将动态创建 DynListComponent 并注入到 host component template 中。

输出

步骤 24: 接下来,运行应用程序,你将看到员工数据以 gallery 格式显示,如下所示 −

gallery format