在Angular中使用NgTemplateOutlet創(chuàng)建可重用組件的流程步驟
簡介
單一職責(zé)原則是指應(yīng)用程序的各個部分應(yīng)該只有一個目的。遵循這個原則可以使您的 Angular 應(yīng)用程序更容易測試和開發(fā)。
在 Angular 中,使用 NgTemplateOutlet 而不是創(chuàng)建特定組件,可以使組件在不修改組件本身的情況下輕松修改為各種用例。
在本文中,您將接受一個現(xiàn)有組件并重寫它以使用 NgTemplateOutlet。
先決條件
要完成本教程,您需要:
- 本地安裝了 Node.js,您可以按照《如何安裝 Node.js 并創(chuàng)建本地開發(fā)環(huán)境》進(jìn)行操作。
- 一些關(guān)于設(shè)置 Angular 項目的熟悉程度。
本教程已使用 Node v16.6.2、npm v7.20.6 和 @angular/core v12.2.0 進(jìn)行驗證。
步驟 1 – 構(gòu)建 CardOrListViewComponent
考慮 CardOrListViewComponent,它根據(jù)其 mode 在 'card' 或 'list' 格式中顯示 items。
它由一個 card-or-list-view.component.ts 文件組成:
import {
Component,
Input
} from '@angular/core';
@Component({
selector: 'card-or-list-view',
templateUrl: './card-or-list-view.component.html'
})
export class CardOrListViewComponent {
@Input() items: {
header: string,
content: string
}[] = [];
@Input() mode: string = 'card';
}
以及一個 card-or-list-view.component.html 模板:
<ng-container [ngSwitch]="mode">
<ng-container *ngSwitchCase="'card'">
<div *ngFor="let item of items">
<h1>{{item.header}}</h1>
<p>{{item.content}}</p>
</div>
</ng-container>
<ul *ngSwitchCase="'list'">
<li *ngFor="let item of items">
{{item.header}}: {{item.content}}
</li>
</ul>
</ng-container>
這是該組件的使用示例:
import { Component } from '@angular/core';
@Component({
template: `
<card-or-list-view
[items]="items"
[mode]="mode">
</card-or-list-view>
`
})
export class UsageExample {
mode = 'list';
items = [
{
header: 'Creating Reuseable Components with NgTemplateOutlet in Angular',
content: 'The single responsibility principle...'
} // ... more items
];
}
該組件沒有單一職責(zé),也不夠靈活。它需要跟蹤其 mode 并知道如何在 card 和 list 視圖中顯示 items。它只能顯示具有 header 和 content 的 items。
讓我們通過使用模板將組件分解為單獨的視圖來改變這一點。
步驟 2 – 理解 ng-template 和 NgTemplateOutlet
為了讓 CardOrListViewComponent 能夠顯示任何類型的 items,我們需要告訴它如何顯示它們。我們可以通過給它一個模板來實現(xiàn)這一點,它可以用來生成 items。
模板將使用 <ng-template> 和從 TemplateRefs 創(chuàng)建的 EmbeddedViewRefs。EmbeddedViewRefs 代表具有自己上下文的 Angular 視圖,是最小的基本構(gòu)建塊。
Angular 提供了一種使用這個從模板生成視圖的概念的方法,即使用 NgTemplateOutlet。
NgTemplateOutlet 是一個指令,它接受一個 TemplateRef 和上下文,并使用提供的上下文生成一個 EmbeddedViewRef??梢酝ㄟ^ let-{{templateVariableName}}="contextProperty" 屬性在模板上訪問上下文,以創(chuàng)建模板可以使用的變量。如果未提供上下文屬性名稱,它將選擇 $implicit 屬性。
這是一個示例:
import { Component } from '@angular/core';
@Component({
template: `
<ng-container *ngTemplateOutlet="templateRef; context: exampleContext"></ng-container>
<ng-template #templateRef let-default let-other="aContextProperty">
<div>
$implicit = '{{default}}'
aContextProperty = '{{other}}'
</div>
</ng-template>
`
})
export class NgTemplateOutletExample {
exampleContext = {
$implicit: 'default context property when none specified',
aContextProperty: 'a context property'
};
}
這是示例的輸出:
<div> $implicit = 'default context property when none specified' aContextProperty = 'a context property' </div>
default 和 other 變量由 let-default 和 let-other="aContextProperty" 屬性提供。
步驟3 – 重構(gòu) CardOrListViewComponent
為了使 CardOrListViewComponent 更加靈活,并允許它顯示任何類型的 items,我們將創(chuàng)建兩個結(jié)構(gòu)型指令來作為模板。這些模板將分別用于卡片和列表項。
這是 card-item.directive.ts:
import { Directive } from '@angular/core';
@Directive({
selector: '[cardItem]'
})
export class CardItemDirective {
constructor() { }
}
這是 list-item.directive.ts:
import { Directive } from '@angular/core';
@Directive({
selector: '[listItem]'
})
export class ListItemDirective {
constructor() { }
}
CardOrListViewComponent 將導(dǎo)入 CardItemDirective 和 ListItemDirective:
import {
Component,
ContentChild,
Input,
TemplateRef
} from '@angular/core';
import { CardItemDirective } from './card-item.directive';
import { ListItemDirective } from './list-item.directive';
@Component({
selector: 'card-or-list-view',
templateUrl: './card-or-list-view.component.html'
})
export class CardOrListViewComponent {
@Input() items: {
header: string,
content: string
}[] = [];
@Input() mode: string = 'card';
@ContentChild(CardItemDirective, {read: TemplateRef}) cardItemTemplate: any;
@ContentChild(ListItemDirective, {read: TemplateRef}) listItemTemplate: any;
}
這段代碼將讀取我們的結(jié)構(gòu)型指令作為 TemplateRefs。
<ng-container [ngSwitch]="mode">
<ng-container *ngSwitchCase="'card'">
<ng-container *ngFor="let item of items">
<ng-container *ngTemplateOutlet="cardItemTemplate"></ng-container>
</ng-container>
</ng-container>
<ul *ngSwitchCase="'list'">
<li *ngFor="let item of items">
<ng-container *ngTemplateOutlet="listItemTemplate"></ng-container>
</li>
</ul>
</ng-container>
這是該組件的使用示例:
import { Component } from '@angular/core';
@Component({
template: `
<card-or-list-view
[items]="items"
[mode]="mode">
<div *cardItem>
靜態(tài)卡片模板
</div>
<li *listItem>
靜態(tài)列表模板
</li>
</card-or-list-view>
`
})
export class UsageExample {
mode = 'list';
items = [
{
header: '使用 NgTemplateOutlet 在 Angular 中創(chuàng)建可重用組件',
content: '單一職責(zé)原則...'
} // ... 更多項
];
}
通過這些更改,CardOrListViewComponent 現(xiàn)在可以根據(jù)提供的模板以卡片或列表形式顯示任何類型的項。目前,模板是靜態(tài)的。
我們需要做的最后一件事是通過為它們提供上下文來使模板變得動態(tài):
<ng-container [ngSwitch]="mode">
<ng-container *ngSwitchCase="'card'">
<ng-container *ngFor="let item of items">
<ng-container *ngTemplateOutlet="cardItemTemplate; context: {$implicit: item}"></ng-container>
</ng-container>
</ng-container>
<ul *ngSwitchCase="'list'">
<li *ngFor="let item of items">
<ng-container *ngTemplateOutlet="listItemTemplate; context: {$implicit: item}"></ng-container>
</li>
</ul>
</ng-container>
這是該組件的使用示例:
import { Component } from '@angular/core';
@Component({
template: `
<card-or-list-view
[items]="items"
[mode]="mode">
<div *cardItem="let item">
<h1>{{item.header}}</h1>
<p>{{item.content}}</p>
</div>
<li *listItem="let item">
{{item.header}}: {{item.content}}
</li>
</card-or-list-view>
`
})
export class UsageExample {
mode = 'list';
items = [
{
header: '使用 NgTemplateOutlet 在 Angular 中創(chuàng)建可重用組件',
content: '單一職責(zé)原則...'
} // ... 更多項
];
}
有趣的是,我們使用了星號前綴和微語法來實現(xiàn)語法糖。這與以下代碼是相同的:
<ng-template cardItem let-item>
<div>
<h1>{{item.header}}</h1>
<p>{{item.content}}</p>
</div>
</ng-template>
就是這樣!我們擁有了原始功能,但現(xiàn)在可以通過修改模板來顯示任何我們想要的內(nèi)容,而 CardOrListViewComponent 的責(zé)任更少了。我們可以向項上下文中添加更多內(nèi)容,比如類似于 ngFor 的 first 或 last,或者顯示完全不同類型的 items。
結(jié)論
在本文中,您將一個現(xiàn)有的組件重寫,以使用 NgTemplateOutlet。
如果您想了解更多關(guān)于 Angular 的內(nèi)容,請查看我們的 Angular 專題頁面,了解相關(guān)練習(xí)和編程項目。
以上就是在Angular中使用NgTemplateOutlet創(chuàng)建可重用組件的流程步驟的詳細(xì)內(nèi)容,更多關(guān)于Angular NgTemplateOutlet可重用組件的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Angular2 組件間通過@Input @Output通訊示例
本篇文章主要介紹了Angular2 組件間通過@Input @Output通訊示例,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2017-08-08
Angular2中如何使用ngx-translate進(jìn)行國際化
本篇文章主要介紹了Angular2中使用ngx-translate進(jìn)行國際化,具有一定的參考價值,感興趣的小伙伴們可以參考一下2017-05-05
angular4應(yīng)用中輸入的最小值和最大值的方法
這篇文章主要介紹了angular4應(yīng)用中輸入的最小值和最大值的方法,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2019-05-05
Angularjs中的事件廣播 —全面解析$broadcast,$emit,$on
下面小編就為大家?guī)硪黄狝ngularjs中的事件廣播 —全面解析$broadcast,$emit,$on。小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考,一起跟隨小編過來看看吧2016-05-05
angular ng-repeat數(shù)組中的數(shù)組實例
下面小編就為大家?guī)硪黄猘ngular ng-repeat數(shù)組中的數(shù)組實例。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2017-02-02
詳解@angular/cli 改變默認(rèn)啟動端口兩種方式
這篇文章主要介紹了詳解@angular/cli 改變默認(rèn)啟動端口兩種方式,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2018-11-11

