在Angular中使用NgTemplateOutlet創(chuàng)建可重用組件的流程步驟
簡(jiǎn)介
單一職責(zé)原則是指應(yīng)用程序的各個(gè)部分應(yīng)該只有一個(gè)目的。遵循這個(gè)原則可以使您的 Angular 應(yīng)用程序更容易測(cè)試和開(kāi)發(fā)。
在 Angular 中,使用 NgTemplateOutlet
而不是創(chuàng)建特定組件,可以使組件在不修改組件本身的情況下輕松修改為各種用例。
在本文中,您將接受一個(gè)現(xiàn)有組件并重寫(xiě)它以使用 NgTemplateOutlet
。
先決條件
要完成本教程,您需要:
- 本地安裝了 Node.js,您可以按照《如何安裝 Node.js 并創(chuàng)建本地開(kāi)發(fā)環(huán)境》進(jìn)行操作。
- 一些關(guān)于設(shè)置 Angular 項(xiàng)目的熟悉程度。
本教程已使用 Node v16.6.2、npm
v7.20.6 和 @angular/core
v12.2.0 進(jìn)行驗(yàn)證。
步驟 1 – 構(gòu)建 CardOrListViewComponent
考慮 CardOrListViewComponent
,它根據(jù)其 mode
在 'card'
或 'list'
格式中顯示 items
。
它由一個(gè) 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'; }
以及一個(gè) 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 ]; }
該組件沒(méi)有單一職責(zé),也不夠靈活。它需要跟蹤其 mode
并知道如何在 card
和 list
視圖中顯示 items
。它只能顯示具有 header
和 content
的 items
。
讓我們通過(guò)使用模板將組件分解為單獨(dú)的視圖來(lái)改變這一點(diǎn)。
步驟 2 – 理解 ng-template 和 NgTemplateOutlet
為了讓 CardOrListViewComponent
能夠顯示任何類(lèi)型的 items
,我們需要告訴它如何顯示它們。我們可以通過(guò)給它一個(gè)模板來(lái)實(shí)現(xiàn)這一點(diǎn),它可以用來(lái)生成 items
。
模板將使用 <ng-template>
和從 TemplateRefs
創(chuàng)建的 EmbeddedViewRefs
。EmbeddedViewRefs
代表具有自己上下文的 Angular 視圖,是最小的基本構(gòu)建塊。
Angular 提供了一種使用這個(gè)從模板生成視圖的概念的方法,即使用 NgTemplateOutlet
。
NgTemplateOutlet
是一個(gè)指令,它接受一個(gè) TemplateRef
和上下文,并使用提供的上下文生成一個(gè) EmbeddedViewRef
??梢酝ㄟ^(guò) let-{{templateVariableName}}="contextProperty"
屬性在模板上訪問(wèn)上下文,以創(chuàng)建模板可以使用的變量。如果未提供上下文屬性名稱(chēng),它將選擇 $implicit
屬性。
這是一個(gè)示例:
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
更加靈活,并允許它顯示任何類(lèi)型的 items
,我們將創(chuàng)建兩個(gè)結(jié)構(gòu)型指令來(lái)作為模板。這些模板將分別用于卡片和列表項(xiàng)。
這是 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é)原則...' } // ... 更多項(xiàng) ]; }
通過(guò)這些更改,CardOrListViewComponent
現(xiàn)在可以根據(jù)提供的模板以卡片或列表形式顯示任何類(lèi)型的項(xiàng)。目前,模板是靜態(tài)的。
我們需要做的最后一件事是通過(guò)為它們提供上下文來(lái)使模板變得動(dòng)態(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àng) ]; }
有趣的是,我們使用了星號(hào)前綴和微語(yǔ)法來(lái)實(shí)現(xiàn)語(yǔ)法糖。這與以下代碼是相同的:
<ng-template cardItem let-item> <div> <h1>{{item.header}}</h1> <p>{{item.content}}</p> </div> </ng-template>
就是這樣!我們擁有了原始功能,但現(xiàn)在可以通過(guò)修改模板來(lái)顯示任何我們想要的內(nèi)容,而 CardOrListViewComponent
的責(zé)任更少了。我們可以向項(xiàng)上下文中添加更多內(nèi)容,比如類(lèi)似于 ngFor
的 first
或 last
,或者顯示完全不同類(lèi)型的 items
。
結(jié)論
在本文中,您將一個(gè)現(xiàn)有的組件重寫(xiě),以使用 NgTemplateOutlet
。
如果您想了解更多關(guān)于 Angular 的內(nèi)容,請(qǐng)查看我們的 Angular 專(zhuān)題頁(yè)面,了解相關(guān)練習(xí)和編程項(xiàng)目。
以上就是在Angular中使用NgTemplateOutlet創(chuàng)建可重用組件的流程步驟的詳細(xì)內(nèi)容,更多關(guān)于Angular NgTemplateOutlet可重用組件的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Angular開(kāi)發(fā)者指南之入門(mén)介紹
本篇文章主要介紹了Angular開(kāi)發(fā)者指南的入門(mén)知識(shí),具有很好的參考價(jià)值。下面跟著小編一起來(lái)看下吧2017-03-03Angular2 組件間通過(guò)@Input @Output通訊示例
本篇文章主要介紹了Angular2 組件間通過(guò)@Input @Output通訊示例,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-08-08Angular2中如何使用ngx-translate進(jìn)行國(guó)際化
本篇文章主要介紹了Angular2中使用ngx-translate進(jìn)行國(guó)際化,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-05-05angular4應(yīng)用中輸入的最小值和最大值的方法
這篇文章主要介紹了angular4應(yīng)用中輸入的最小值和最大值的方法,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2019-05-05Angularjs中的事件廣播 —全面解析$broadcast,$emit,$on
下面小編就為大家?guī)?lái)一篇Angularjs中的事件廣播 —全面解析$broadcast,$emit,$on。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考,一起跟隨小編過(guò)來(lái)看看吧2016-05-05AngularJS ui-router刷新子頁(yè)面路由的方法
這篇文章主要介紹了AngularJS ui-router刷新子頁(yè)面路由的方法,網(wǎng)上雖然有很多種方法,但是都不適合小編,今天小編給大家分享一個(gè)還不錯(cuò)的方法,需要的朋友可以參考下2018-07-07angular ng-repeat數(shù)組中的數(shù)組實(shí)例
下面小編就為大家?guī)?lái)一篇angular ng-repeat數(shù)組中的數(shù)組實(shí)例。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-02-02詳解@angular/cli 改變默認(rèn)啟動(dòng)端口兩種方式
這篇文章主要介紹了詳解@angular/cli 改變默認(rèn)啟動(dòng)端口兩種方式,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-11-11