网站首页 » 前端开发 » Angular 2+ » Angular 2+ 动态组件
上一篇:
下一篇:

Angular 2+ 动态组件

Angular 2+ 中的动态组件怎么用?这对于像我这样的初学者来说无疑是一个很大的挑战,特别是在看官方介绍文档和示例时,倍感压力。为此,本文用尽可能简单的例子来实现Angular 2+ 动态组件加载。

在实现动态组件之前,我们就要有心理准备,因为在这个简单的示例中涉及到了比较多的知识点,包括但不限于:

  • ViewChild
  • ViewContainerRef
  • ComponentFactoryResolver
  • AfterViewInit
  • Directive

ViewChild:属性装饰器,用来从模板视图中获取对应的元素,可通过模板变量获取,获取时可以通过 read 属性设置查询的条件,把此视图转为不同的实例。

ViewContainerRef:表示一个容器,其中可以附加一个或多个视图。

ComponentFactoryResolver:组件工厂原型,可以用它来为每个具体的组件解析出一个 ComponentFactory。然后 ComponentFactory 会为每一个组件创建一个实例。

AfterViewInit:生命周期勾子,初始化完组件视图及其子视图之后调用。

Directive:指令,可以通过它来封装一些常用的功能。

基础的东西说完之后,此时此刻就是上码的时机了:

我们选准备好两个用于动态加载的组件:

dynamic.first.component.ts
import { Component, OnInit } from '@angular/core';

@Component({
    selector: 'dynamic-first-component',
    template: `<div>dynamic-first-component</div>`
})

export class DynamicFirstComponent implements OnInit {
    constructor() { }
    ngOnInit(): void { };
}
dynamic.second.component.ts
import { Component, OnInit } from '@angular/core';

@Component({
    selector: 'dynamic-second-component',
    template: `<div>dynamic-second-component</div>`
})

export class DynamicSecondComponent implements OnInit {
    constructor() { }
    ngOnInit(): void { }
}

上面的代码几乎没有什么技术含量,看一眼就好。接着我们来定义一个 Drective。

dynamic.directive.ts
import { Directive, ViewContainerRef } from '@angular/core';

@Directive({
    selector: '[component-host]',
})
export class DynamicDirective {
    constructor(public _viewContainerRef: ViewContainerRef) { }
}

这个指令也相当的简单,只做了一件事,往构造函数里注入了 ViewContainerRef。它可以让我们访问到这个被我们用于动态组件的宿主的元素。

app.component.ts
import { Component, ViewChild, AfterViewInit, ComponentFactoryResolver } from '@angular/core';
import { DynamicDirective } from './dynamic.directive';
import { DynamicFirstComponent } from './dynamic.first.component';
import { DynamicSecondComponent } from './dynamic.second.component';

@Component({
  selector: 'app-root',
  template: `
    <button (click)="firstComponent()">加载组件一</button>
    <button (click)="secondComponent()">加载组件二</button>
    <ng-template component-host></ng-template>
  `
})

export class AppComponent implements AfterViewInit {


  @ViewChild(DynamicDirective) componentHost: DynamicDirective;

  constructor(private _componentFactoryResolver: ComponentFactoryResolver) { }

  ngAfterViewInit() {
    this.switchComponent(DynamicFirstComponent);
  }

  firstComponent(): void {
    this.switchComponent(DynamicFirstComponent);
  }

  secondComponent(): void {
    this.switchComponent(DynamicSecondComponent);
  }

  switchComponent(dyComponent) {
    let componentFactory = this._componentFactoryResolver.resolveComponentFactory(dyComponent);
    let viewContainerRef = this.componentHost._viewContainerRef;
    viewContainerRef.clear();
    viewContainerRef.createComponent(componentFactory);
  }
}

在这个组件中,我们添加了两个按钮,用于动态切换组件。紧跟在按钮后面的 <ng-template></ng-template> 标签就是用来载入组件的,为什么要用 <ng-template></ng-template>,因为它不会产生额外的代码。 往构造函数中注入 ComponentFactoryResolver ,然后在 switchComponent 方法中通过它来获取需要动态加载的组件。

createComponent() 方法会返回一个引用,指向这个刚刚加载的组件。 使用这个引用就可以与该组件进行交互,比如设置它的属性或调用它的方法。

上面这些都做完后,我们就需要在 app.module.ts 中添加相关的资源。

app.module.ts
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { AppComponent } from './app.component';
import { DynamicFirstComponent } from './dynamic.first.component';
import { DynamicSecondComponent } from './dynamic.second.component';
import { DynamicDirective } from './dynamic.directive';

@NgModule({
  declarations: [
    AppComponent,
    DynamicFirstComponent,
    DynamicSecondComponent,
    DynamicDirective
  ],
  imports: [
    BrowserModule
  ],
  entryComponents: [
    DynamicFirstComponent,
    DynamicSecondComponent
  ],

  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

导入模板、指令,并在添加到 declarations 中,需要注意的是我们还需要把将要动态加载的组件添加到 entryComponents 中。

  • 微信扫一扫,赏我

  • 支付宝扫一扫,赏我

声明

原创文章,不经本站同意,不得以任何形式转载,如有不便,请多多包涵!

本文永久链接:http://yunkus.com/angular-core-knowledge-dynamic-component-loader/

Leave a Reply

Your email address will not be published. Required fields are marked *

评论 END