欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

詳解Angular 4.x 動態(tài)創(chuàng)建組件

 更新時間:2017年04月25日 14:38:09   作者:semlinker  
本篇文章主要介紹了詳解Angular 4.x 動態(tài)創(chuàng)建組件,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧

動態(tài)創(chuàng)建組件

這篇文章我們將介紹在 Angular 中如何動態(tài)創(chuàng)建組件。

定義 AlertComponent 組件

首先,我們需要定義一個組件。

exe-alert.component.ts

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

@Component({
  selector: "exe-alert",
  template: `
   <h1>Alert {{type}}</h1>
  `,
})
export class AlertComponent {
  @Input() type: string = "success";
}

上面代碼中,我們定義了一個簡單的 alert 組件,該組件有一個輸入屬性 type ,用于讓用戶自定義提示的類型。我們的自定義組件最終是一個實際的 DOM 元素,因此如果我們需要在頁面中插入該元素,我們就需要考慮在哪里放置該元素。

創(chuàng)建組件容器

在 Angular 中放置組件的地方稱為 container 容器。接下來,我們將在 exe-app 組件中創(chuàng)建一個模板元素,此外我們使用模板變量的語法,聲明一個模板變量。接下來模板元素 <ng-template> 將會作為我們的組件容器,具體示例如下:

app.component.ts

import { Component } from '@angular/core';

@Component({
 selector: 'exe-app',
 template: `
  <ng-template #alertContainer></ng-template>
 `
})
export class AppComponent { }

友情提示:容器可以是任意的 DOM 元素或組件。

在 AppComponent 組件中,我們可以通過 ViewChild 裝飾器來獲取視圖中的模板元素,如果沒有指定第二個查詢參數(shù),則默認(rèn)返回的組件實例或相應(yīng)的 DOM 元素,但這個示例中,我們需要獲取 ViewContainerRef 實例。

ViewContainerRef 用于表示一個視圖容器,可添加一個或多個視圖。通過 ViewContainerRef 實例,我們可以基于 TemplateRef 實例創(chuàng)建內(nèi)嵌視圖,并能指定內(nèi)嵌視圖的插入位置,也可以方便對視圖容器中已有的視圖進(jìn)行管理。簡而言之,ViewContainerRef 的主要作用是創(chuàng)建和管理內(nèi)嵌視圖或組件視圖。

根據(jù)以上需求,更新后的代碼如下:

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

@Component({
 selector: 'exe-app',
 template: `
  <ng-template #alertContainer></ng-template>
 `
})
export class AppComponent {
 @ViewChild("alertContainer", { read: ViewContainerRef }) container: ViewContainerRef;
}

動態(tài)創(chuàng)建組件

接下來,在 AppComponent 組件中,我們來添加兩個按鈕,用于創(chuàng)建 AlertComponent 組件。

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

@Component({
 selector: 'exe-app',
 template: `
  <ng-template #alertContainer></ng-template>
  <button (click)="createComponent('success')">Create success alert</button>
  <button (click)="createComponent('danger')">Create danger alert</button>
 `
})
export class AppComponent {
 @ViewChild("alertContainer", { read: ViewContainerRef }) container: ViewContainerRef;
}

在我們定義 createComponent() 方法前,我們需要注入 ComponentFactoryResolver 服務(wù)對象。該 ComponentFactoryResolver 服務(wù)對象中,提供了一個很重要的方法 - resolveComponentFactory() ,該方法接收一個組件類作為參數(shù),并返回 ComponentFactory 。

ComponentFactoryResolver 抽象類:

export abstract class ComponentFactoryResolver {
 static NULL: ComponentFactoryResolver = new _NullComponentFactoryResolver();
 abstract resolveComponentFactory<T>(component: Type<T>): ComponentFactory<T>;
}

在 AppComponent 組件構(gòu)造函數(shù)中,注入 ComponentFactoryResolver 服務(wù):

constructor(private resolver: ComponentFactoryResolver) {}

接下來我們再來看一下 ComponentFactory 抽象類:

export abstract class ComponentFactory<C> {
 abstract get selector(): string;
 abstract get componentType(): Type<any>;
 
 // selector for all <ng-content> elements in the component.
 abstract get ngContentSelectors(): string[];
 // the inputs of the component.
 abstract get inputs(): {propName: string, templateName: string}[];
 // the outputs of the component.
 abstract get outputs(): {propName: string, templateName: string}[];
 // Creates a new component.
 abstract create(
   injector: Injector, projectableNodes?: any[][], rootSelectorOrNode?: string|any,
   ngModule?: NgModuleRef<any>): ComponentRef<C>;
}

通過觀察 ComponentFactory 抽象類,我們知道可以通過調(diào)用 ComponentFactory 實例的 create() 方法,來創(chuàng)建組件。介紹完上面的知識,我們來實現(xiàn) AppComponent 組件的 createComponent() 方法:

createComponent(type) {
  this.container.clear(); 
  const factory: ComponentFactory = 
   this.resolver.resolveComponentFactory(AlertComponent);
  this.componentRef: ComponentRef = this.container.createComponent(factory);
}

接下來我們來分段解釋一下上面的代碼。

this.container.clear();

每次我們需要創(chuàng)建組件時,我們需要刪除之前的視圖,否則組件容器中會出現(xiàn)多個視圖 (如果允許多個組件的話,就不需要執(zhí)行清除操作 )。

復(fù)制代碼 代碼如下:

const factory: ComponentFactory = this.resolver.resolveComponentFactory(AlertComponent);

正如我們之前所說的,resolveComponentFactory() 方法接受一個組件并返回如何創(chuàng)建組件的 ComponentFactory 實例。

復(fù)制代碼 代碼如下:

this.componentRef: ComponentRef = this.container.createComponent(factory);

在上面代碼中,我們調(diào)用容器的 createComponent() 方法,該方法內(nèi)部將調(diào)用 ComponentFactory 實例的 create() 方法創(chuàng)建對應(yīng)的組件,并將組件添加到我們的容器。

現(xiàn)在我們已經(jīng)能獲取新組件的引用,即可以我們可以設(shè)置組件的輸入類型:

this.componentRef.instance.type = type;

同樣我們也可以訂閱組件的輸出屬性,具體如下:

this.componentRef.instance.output.subscribe(event => console.log(event));

另外不能忘記銷毀組件:

ngOnDestroy() {
 this.componentRef.destroy(); 
}

最后我們需要將動態(tài)組件添加到 NgModule 的 entryComponents 屬性中:

@NgModule({
 ...,
 declarations: [AppComponent, AlertComponent],
 bootstrap: [AppComponent],
 entryComponents: [AlertComponent],
})
export class AppModule { }

完整示例

exe-alert.component.ts

import { Component, Input, Output, EventEmitter } from '@angular/core';

@Component({
  selector: "exe-alert",
  template: `
   <h1 (click)="output.next(type)">Alert {{type}}</h1>
  `,
})
export class AlertComponent {
  @Input() type: string = "success";
  @Output() output = new EventEmitter();
}

app.component.ts

import {
 Component, ViewChild, ViewContainerRef, ComponentFactory,
 ComponentRef, ComponentFactoryResolver, OnDestroy
} from '@angular/core';
import { AlertComponent } from './exe-alert.component';

@Component({
 selector: 'exe-app',
 template: `
  <ng-template #alertContainer></ng-template>
  <button (click)="createComponent('success')">Create success alert</button>
  <button (click)="createComponent('danger')">Create danger alert</button>
 `
})
export class AppComponent implements OnDestroy {
 componentRef: ComponentRef<AlertComponent>;

 @ViewChild("alertContainer", { read: ViewContainerRef }) container: ViewContainerRef;

 constructor(private resolver: ComponentFactoryResolver) { }

 createComponent(type: string) {
  this.container.clear();
  const factory: ComponentFactory<AlertComponent> =
   this.resolver.resolveComponentFactory(AlertComponent);
  this.componentRef = this.container.createComponent(factory);
  this.componentRef.instance.type = type;
   this.componentRef.instance.output.subscribe((msg: string) => console.log(msg));
 }

 ngOnDestroy() {
  this.componentRef.destroy()
 }
}

app.module.ts

import { NgModule, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';

import { AppComponent } from './app.component';
import { AlertComponent } from './exe-alert.component';

@NgModule({
 imports: [BrowserModule],
 declarations: [AppComponent, AlertComponent],
 bootstrap: [AppComponent],
 entryComponents: [AlertComponent],
 schemas: [CUSTOM_ELEMENTS_SCHEMA]
})
export class AppModule { }

總結(jié)

  • 獲取裝載動態(tài)組件的容器

  • 在組件類的構(gòu)造函數(shù)中,注入 ComponentFactoryResolver 對象

  • 調(diào)用 ComponentFactoryResolver 對象的 resolveComponentFactory() 方法創(chuàng)建 ComponentFactory 對象

  • 調(diào)用組件容器對象的 createComponent() 方法創(chuàng)建組件并自動添加動態(tài)組件到組件容器中

  • 基于返回的 ComponentRef 組件實例,配置組件相關(guān)屬性 (可選)

  • 在模塊 Metadata 對象的 entryComponents 屬性中添加動態(tài)組件

    • declarations - 用于指定屬于該模塊的指令和管道列表

    • entryComponents - 用于指定在模塊定義時,需要編譯的組件列表。對于列表中聲明的每個組件,Angular 將會創(chuàng)建對應(yīng)的一個 ComponentFactory 對象,并將其存儲在 ComponentFactoryResolver 對象中

我有話說

<ng-template> <ng-container> 有什么區(qū)別?

通常情況下,當(dāng)我們使用結(jié)構(gòu)指令時,我們需要添加額外的標(biāo)簽來封裝內(nèi)容,如使用 *ngIf 指令:

<section *ngIf="show">
 <div>
  <h2>Div one</h2>
 </div>
 <div>
  <h2>Div two</h2>
 </div>
</section>

上面示例中,我們在 section 標(biāo)簽上應(yīng)用了 ngIf 指令,從而實現(xiàn) section 標(biāo)簽內(nèi)容的動態(tài)顯示。這種方式有個問題是,我們必須添加額外的 DOM 元素。要解決該問題,我們可以使用 <ng-template> 的標(biāo)準(zhǔn)語法 (非*ngIf語法糖):

<ng-template [ngIf]="show">
 <div>
  <h2>Div one</h2>
 </div>
 <div>
  <h2>Div two</h2>
 </div>
</ng-template>

問題是解決了但我們不再使用 * 語法糖語法,這樣會導(dǎo)致我們代碼的不統(tǒng)一。雖然解決了問題,但又帶來了新問題。那我們還有其它的方案么?答案是有的,我們可以使用 ng-container 指令。

<ng-container>

<ng-container> 是一個邏輯容器,可用于對節(jié)點進(jìn)行分組,但不作為 DOM 樹中的節(jié)點,它將被渲染為 HTML中的 comment 元素。使用 <ng-container> 的示例如下:

<ng-container *ngIf="show">
 <div>
  <h2>Div one</h2>
 </div>
 
 <div>
  <h2>Div two</h2>
 </div>
 </ng-container>

有時我們需要根據(jù) switch 語句,動態(tài)顯示文本,這時我們需要添加一個額外的標(biāo)簽如 <span> ,具體示例如下:

<div [ngSwitch]="value">
 <span *ngSwitchCase="0">Text one</span>
 <span *ngSwitchCase="1">Text two</span>
</div>

針對這種情況,理論上我們是不需要添加額外的 <span> 標(biāo)簽,這時我們可以使用 ng-container 來解決這個問題:

<div [ngSwitch]="value">
 <ng-container *ngSwitchCase="0">Text one</ng-container>
 <ng-container *ngSwitchCase="1">Text two</ng-container>
</div>

介紹完 ng-container 指令,我們來分析一下它跟 ng-template 指令有什么區(qū)別?我們先看以下示例:

<ng-template>
  <p> In template, no attributes. </p>
</ng-template>

<ng-container>
  <p> In ng-container, no attributes. </p>
</ng-container>

以上代碼運行后,瀏覽器中輸出結(jié)果是:

In ng-container, no attributes.

<ng-template> 中的內(nèi)容不會顯示。當(dāng)在上面的模板中添加 ngIf 指令:

<template [ngIf]="true">
  <p> ngIf with a template.</p>
</template>

<ng-container *ngIf="true">
  <p> ngIf with an ng-container.</p>
</ng-container>

以上代碼運行后,瀏覽器中輸出結(jié)果是:

ngIf with a template.
ngIf with an ng-container.

現(xiàn)在我們來總結(jié)一下 <ng-template> <ng-container> 的區(qū)別:

  1. <ng-template> :使用 * 語法糖的結(jié)構(gòu)指令,最終都會轉(zhuǎn)換為 <ng-template> 或 <template> 模板指令,模板內(nèi)的內(nèi)容如果不進(jìn)行處理,是不會在頁面中顯示的。
  2. <ng-container>:是一個邏輯容器,可用于對節(jié)點進(jìn)行分組,但不作為 DOM 樹中的節(jié)點,它將被渲染為 HTML中的 comment 元素,它可用于避免添加額外的元素來使用結(jié)構(gòu)指令。

最后再來看一個 <ng-container> 的使用示例:

模板定義

<div>
 <ng-container *ngIf="true">
   <h2>Title</h2>
   <div>Content</div>
  </ng-container>
</div>

渲染結(jié)果

<div>
  <!--bindings={
 "ng-reflect-ng-if": "true"
  }--><!---->
  <h2>Title</h2>
  <div>Content</div>
</div>

TemplateRef 與 ViewContainerRef 有什么作用?

TemplateRef

用于表示內(nèi)嵌的 template 模板元素,通過 TemplateRef 實例,我們可以方便創(chuàng)建內(nèi)嵌視圖(Embedded Views),且可以輕松地訪問到通過 ElementRef 封裝后的 nativeElement。需要注意的是組件視圖中的 template 模板元素,經(jīng)過渲染后會被替換成 comment 元素。

ViewContainerRef

用于表示一個視圖容器,可添加一個或多個視圖。通 ViewContainerRef 實例,我們可以基于 TemplateRef 實例創(chuàng)建內(nèi)嵌視圖,并能指定內(nèi)嵌視圖的插入位置,也可以方便對視圖容器中已有的視圖進(jìn)行管理。簡而言之,ViewContainerRef 的主要作用是創(chuàng)建和管理內(nèi)嵌視圖或組件視圖。(本示例就是通過 ViewContainerRef 對象提供的 API來動態(tài)地創(chuàng)建組件視圖)。

ViewChild 裝飾器還支持哪些查詢條件?

ViewChild 裝飾器用于獲取模板視圖中的元素,它支持 Type 類型或 string 類型的選擇器,同時支持設(shè)置 read 查詢條件,以獲取不同類型的實例。

export interface ViewChildDecorator {
 // Type類型:@ViewChild(ChildComponent)
 // string類型:@ViewChild('tpl', { read: ViewContainerRef })
 (selector: Type<any>|Function|string, {read}?: {read?: any}): any;

 new (selector: Type<any>|Function|string, 
   {read}?: {read?: any}): ViewChild;
}

以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • AngularJS中取消對HTML片段轉(zhuǎn)義的方法例子

    AngularJS中取消對HTML片段轉(zhuǎn)義的方法例子

    這篇文章主要介紹了AngularJS中取消對HTML片段轉(zhuǎn)義的方法例子,在一些需要顯示HTML的地方,就要取消AngularJS的轉(zhuǎn)義,本文就介紹了這種方法,需要的朋友可以參考下
    2015-01-01
  • SeaJS 與 RequireJS 的差異對比

    SeaJS 與 RequireJS 的差異對比

    這篇文章主要介紹了SeaJS 與 RequireJS 的差異對比,本文主要對CMD規(guī)范和AMD規(guī)范的弊端做了對比,并做出了一個總結(jié),需要的朋友可以參考下
    2014-12-12
  • angular.bind使用心得

    angular.bind使用心得

    這篇文章主要介紹了angular.bind使用心得,以及個人對于angular.bind的理解,這里分享給大家,希望大家能夠喜歡。
    2015-10-10
  • AngularJs基本特性解析(一)

    AngularJs基本特性解析(一)

    angularjs是javascript的一個框架,通過script標(biāo)簽添加到網(wǎng)頁中。這篇文章主要介紹了AngularJs基本特性解析(一)的相關(guān)資料,需要的朋友可以參考下
    2016-07-07
  • angular內(nèi)容投影詳解

    angular內(nèi)容投影詳解

    這篇文章主要為大家介紹了angular內(nèi)容投影,具有一定的參考價值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助
    2021-12-12
  • AngularJS Controller作用域

    AngularJS Controller作用域

    這篇文章主要為大家詳細(xì)介紹了AngularJS Controller的作用域,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-01-01
  • 如何以Angular的姿勢打開Font-Awesome詳解

    如何以Angular的姿勢打開Font-Awesome詳解

    這篇文章主要給大家介紹了關(guān)于如何以Angular的姿勢打開Font-Awesome的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家學(xué)習(xí)或者使用Angular具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧。
    2018-04-04
  • Angular中使用嵌套Form的詳細(xì)步驟

    Angular中使用嵌套Form的詳細(xì)步驟

    Angular響應(yīng)式表單使用顯式的、不可變的方式,管理表單在特定的時間點上的狀態(tài),下面這篇文章主要給大家介紹了關(guān)于Angular中使用嵌套Form的詳細(xì)步驟,需要的朋友可以參考下
    2022-04-04
  • 詳解AngularJs中$sce與$sceDelegate上下文轉(zhuǎn)義服務(wù)

    詳解AngularJs中$sce與$sceDelegate上下文轉(zhuǎn)義服務(wù)

    這篇文章給大家詳細(xì)介紹了AngularJs提供的嚴(yán)格上下文轉(zhuǎn)義服務(wù)$sce與$sceDelegate,文中介紹的很詳細(xì),有需要的朋友們可以參考借鑒。
    2016-09-09
  • angularjs路由傳值$routeParams詳解

    angularjs路由傳值$routeParams詳解

    這篇文章主要為大家詳細(xì)介紹了angularjs路由傳值$routeParams的相關(guān)資料,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-09-09

最新評論