码迷,mamicode.com
首页 > 其他好文 > 详细

[Anglar]-使用ComponentFactoryResolver动态产生Component

时间:2020-06-08 23:51:28      阅读:112      评论:0      收藏:0      [点我收藏+]

标签:ntc   load   地址   change   angular   from   nta   优秀的程序员   box   

      Angular提供了ComponentFactoryResolver,来协助我们在项目中动态实现Component,而不是把页面需要的所有的组件都写道view里,根据不同的条件来判断显示目标component,当遇到程序现实复杂的需求时非常好用,写出的代码易理解也易维护。今天我们就来看看如何透过ComponentFactoryResolver来动态产生需要的Component。

需求说明

  首先看看以下画面,我们希望点选radio时,可以依照不同的选择切换不同的Component。

  技术图片

  先不考虑动态产生,只有3个component时,代码可以很简单通过ngIf来判断component是否要被产生,可读性也不至于太差。

技术图片
 1 <input type="radio" id="showComponentA" name="showComponent" value="componentA" [(ngModel)]="selectedComponentName"/>
 2 <label for="showComponentA">组件 A</label>
 3 
 4 <input type="radio" id="showComponentB" name="showComponent" value="componentB" [(ngModel)]="selectedComponentName"/>
 5 <label for="showComponentB">组件 B</label>
 6 
 7 <input type="radio" id="showComponentC" name="showComponent" value="componentC" [(ngModel)]="selectedComponentName"/>
 8 <label for="showComponentC">组件 C</label>
 9 
10 <app-component-a *ngIf="selectedComponentName === ‘componentA‘"></app-component-a>
11 <app-component-b *ngIf="selectedComponentName === ‘componentB‘"></app-component-b>
12 <app-component-c *ngIf="selectedComponentName === ‘componentC‘"></app-component-c>
View Code

  不过当选想变得很多,或者可选项通过后端决定等等较为复杂的情况时,代码很容易变得杂乱不好维护。身为优秀的程序员,自然不希望这种情况发生,因此我们需要通过动态的方式,来产生component。也就是今天的主角--ComponentFactoryResolver。

建立DynamicComponentDirective

  首先我们先建立一个directive,并注入ViewContainerRef,ViewContainerRef可以让我们知道目前所在的HTML元素包含的view内容,也可以通过它来改变view的结果(例如:动态的产生component,或者动态的移除component等等)。

  执行命令: ng generate directive DynamicComponent

  

技术图片
 1 import { Directive, ViewContainerRef } from ‘@angular/core‘;
 2 
 3 @Directive({
 4   selector: ‘[appDynamicComponent]‘
 5 })
 6 export class DynamicComponentDirective {
 7 
 8   constructor(public viewcontainerRef: ViewContainerRef) { }
 9 
10 }
View Code

  接着我们需要套用这个directive到需要动态产生component的容器上,我们可以简单地套用ng-template就好,把原来的view代码改成如下

技术图片
 1 <input type="radio" id="showComponentA" name="showComponent" value="componentA" (change)="displayComponent(‘componentA‘)"/>
 2 <label for="showComponentA">组件 A</label>
 3 
 4 <input type="radio" id="showComponentB" name="showComponent" value="componentB" (change)="displayComponent(‘componentB‘)"/>
 5 <label for="showComponentB">组件 B</label>
 6 
 7 <input type="radio" id="showComponentC" name="showComponent" value="componentC" (change)="displayComponent(‘componentC‘)"/>
 8 <label for="showComponentC">组件 C</label>
 9 
10 <ng-template appDynamicComponent></ng-template>
View Code

  原来的3行components就浓缩成只剩下一行了,同时我们也不用看到一堆脏脏的ngIf了,view的呈现顿时清爽可许多;同时我们替radiobox加入change事件,要决定动态产生哪一个component,而接下来就是动态产生的重头戏。

使用ComponentFactoryResolver动态产生Component

技术图片
 1 import { Component, ViewChild, ComponentFactoryResolver } from ‘@angular/core‘;
 2 import { DynamicComponentDirective } from ‘./dynamic-component.directive‘;
 3 import { DynamicComponentService } from ‘./dynamic-component.service‘;
 4 
 5 @Component({
 6   selector: ‘app-root‘,
 7   templateUrl: ‘./app.component.html‘,
 8   styleUrls: [‘./app.component.css‘],
 9   providers: [DynamicComponentService]
10 })
11 export class AppComponent {
12   @ViewChild(DynamicComponentDirective) componentHost: DynamicComponentDirective;
13   constructor(private dynamicComponentService: DynamicComponentService,
14               private componentFactoryResolver: ComponentFactoryResolver) {
15   }
16   displayComponent(componentName: string) {
17     const componentFactory = this.componentFactoryResolver.resolveComponentFactory(
18       this.dynamicComponentService.getComponent(componentName)
19     );
20     const viewContainerRef = this.componentHost.viewcontainerRef;
21     viewContainerRef.clear();
22     viewContainerRef.createComponent(componentFactory);
23   }
24 }
View Code

  在这边我们做了这样几件事:

  1.使用ViewChild取得要动态创建component的directive(componentHost)

  2.注入ComponentFactoryResolver

  3.在displayComponent中,使用ComponentFactoryResolver.ResolveComponentFactory来创建一个ComponentFactory

  4.通过componentHost的ViewContainerRef,将内容清空(viewcontainerRef.clear())

  5.通过viewcontainerRef.creatComponent(componentFactory),产生我们需要的component并放入componetHost之中

  至于 如何产生哪一个component,这里我们额外建立了一个DynamicComponentService服务,来决定产生哪一个component

  执行命令: ng generate service DynamicComponent

技术图片
 1 import { Injectable } from ‘@angular/core‘;
 2 import { ComponentAComponent } from ‘./component-a/component-a.component‘;
 3 import { ComponentBComponent } from ‘./component-b/component-b.component‘;
 4 import { ComponentCComponent } from ‘./component-c/component-c.component‘;
 5 
 6 @Injectable({
 7   providedIn: ‘root‘
 8 })
 9 export class DynamicComponentService {
10   private components = {
11     componentA: ComponentAComponent,
12     componentB: ComponentBComponent,
13     componentC: ComponentCComponent
14   };
15   constructor() { }
16 
17   getComponent(componentName: string) {
18     return this.components[componentName];
19   }
20 }
View Code

在Module加入entryComponents

接下来就是最后一步了,由于我们的Component是动态产生,而不是直接透过View上的selector产生的,为了确保能够产生动态的Component,我们还需要在所属的Module中加入一个entryComponents阵列

技术图片
 1 import { BrowserModule } from ‘@angular/platform-browser‘;
 2 import { NgModule } from ‘@angular/core‘;
 3 import { FormsModule } from ‘@angular/forms‘;
 4 
 5 import { AppComponent } from ‘./app.component‘;
 6 import { ComponentAComponent } from ‘./component-a/component-a.component‘;
 7 import { ComponentBComponent } from ‘./component-b/component-b.component‘;
 8 import { ComponentCComponent } from ‘./component-c/component-c.component‘;
 9 import { DynamicComponentDirective } from ‘./dynamic-component.directive‘;
10 
11 @NgModule({
12   declarations: [
13     AppComponent,
14     ComponentAComponent,
15     ComponentBComponent,
16     ComponentCComponent,
17     DynamicComponentDirective
18   ],
19   imports: [
20     BrowserModule,
21     FormsModule
22   ],
23   providers: [],
24   bootstrap: [AppComponent],
25   entryComponents: [
26     ComponentAComponent,
27     ComponentBComponent,
28     ComponentCComponent
29   ]
30 })
31 export class AppModule { }
View Code

 完整代码地址:https://github.com/1weidong/component-factory-resolver/tree/master

[Anglar]-使用ComponentFactoryResolver动态产生Component

标签:ntc   load   地址   change   angular   from   nta   优秀的程序员   box   

原文地址:https://www.cnblogs.com/wei-dong/p/13066696.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!