*ngTemplateOutlet指令的实际场景是什么



我正在阅读有关*ngTemplateOutlet指令的内容。该指令的用途是通过模板引用和上下文对象作为参数来动态实例化模板。

我想知道的是,我们在Angular中有很多东西可以实现与*ngTemplateOutlet相同的结果,例如:

  1. 我们可以有多个*ngIf,它们可以基于同一组件内的组件变量值来呈现不同的模板。以类似的方式,我们有[ngSwitch],它将根据不同的值为我们呈现不同的模板。

  2. 我们可以通过引用相应变量的模板引用变量来使用*ngIf的引用。

对于前一种情况:

<div *ngIf="condition1"> Content 1 </div>
<div *ngIf="condition2"> Content 2 </div>
<div *ngIf="condition3"> Content 3 </div>

对于后者:

<ng-container *ngIf="condition then myTemplate else otherTemplate"></ng-container>
<ng-template #myTemplate> Some content... </ng-template>
<ng-template #otherTemplate> Some content... </ng-template>

如果我们的武器库中有这样的方法,*ngTemplateOutlet还能增加什么价值?

在哪些实际用例中(如果有的话),我们不能使用上述方法,而应该使用*ngTemplateOutlet指令,或者这只是另一种可以选择的方法来获得相同的结果?

角度模板出口可用于在视图的各个部分中插入一个公共模板,这些部分不是由循环生成的或受条件约束的。例如,您可以为一家公司的徽标定义一个模板,并将其插入页面中的几个位置:

<div>
<ng-container *ngTemplateOutlet="companyLogoTemplate"></ng-container>
<h1>Company History</h1>
<div>{{companyHistory}}</div>
</div>
<form (ngSubmit)="onSubmit()">
<ng-container *ngTemplateOutlet="companyLogoTemplate"></ng-container>
<h1>User info</h1>
<label>Name:</label><input type="text" [(ngModel)]="userName" />
<label>Account ID:</label><input type="text" [(ngModel)]="accountId" />
<button>Submit</button>
</form>
<div class="footer">
<ng-container *ngTemplateOutlet="companyLogoTemplate"></ng-container>
</div>
<ng-template #companyLogoTemplate>
<div class="companyLogo">
<img [src]="logoSourceUrl">
<label>The ACME company, {{employeeCount}} people working for you!</label>
</div>
</ng-template>

模板和模板出口也有助于使组件可配置。下面的例子来自Angular大学的这篇文章。

选项卡容器组件定义默认的选项卡标头模板,但允许使用定义为输入属性的自定义模板覆盖它。然后将适当的模板(默认或自定义)插入到具有模板出口的视图中:

@Component({
selector: 'tab-container',
template: `
<ng-template #defaultTabButtons>
<div class="default-tab-buttons">
...
</div>
</ng-template>
<ng-container *ngTemplateOutlet="headerTemplate || defaultTabButtons"></ng-container>
... rest of tab container component ...
`
})
export class TabContainerComponent {
@Input() headerTemplate: TemplateRef<any>; // Custom template provided by parent
}

在父组件中,您定义自定义选项卡标题模板,并将其传递给选项卡容器组件:

@Component({
selector: 'app-root',
template: `      
<ng-template #customTabButtons>
<div class="custom-class">
<button class="tab-button" (click)="login()">
{{loginText}}
</button>
<button class="tab-button" (click)="signUp()">
{{signUpText}}
</button>
</div>
</ng-template>
<tab-container [headerTemplate]="customTabButtons"></tab-container>      
`
})
export class AppComponent implements OnInit {
...
}

你可以在alligator.io.的这篇博客文章中看到另一个高级用例

使*ngTemplateOutlet比*ng内容更强大的一点是,当您将其与[ngTemplateOutletContext]输入一起使用时。这使您能够创建一个完全唯一的模板,该模板可以使用组件中的状态。

我已经用它创建了一个选择组件,该组件通过不同的模板为每个客户端提供唯一的样式,但共享完全相同的代码。这是一个StackBlitz链接,也是我在indepht.dev.上关于它的文章

与使用*ngIfs相比,*ngTemplateOutlets的一个好处是,如果组件只由单个客户端使用,那么它不需要依赖于外部包,即Icon lib。

你有一个非常有效的问题。如果可以通过简单的ifswitch情况来实现,为什么要使用*ngTemplateOutlet

独立组件

您之所以有这些想法,是因为您正在考虑一个独立的组件级别。换句话说,所有条件、模板都在同一个组件中。我们可以根据一定的条件很容易地选择模板。

库组件

动态模板

当我说库组件时,它意味着通用的可重用组件,例如AutocompleterTypeahead等。这些组件提供了功能部分,但它们允许开发人员根据自己的需求选择自己的template

现在的问题是,这些模板并不驻留在Autocompleter中,而是来自其@ContentChild

例如:

<ng-autocompleter>
<ng-template #item let-item>{{item.name}}</ng-template>
<ng-autocompleter>

在上面的例子中,<ng-template>被定义为开发者稍后的点时间,而不是<ng-autocompleter>的直接部分。

模板上下文

无论何时开发高度配置的组件,模板上下文都非常重要。获取动态模板(html)不足以达到目的。我们需要将该值绑定到ng-template。由于ng模板不在ng-autocompleter的部分中,我们需要传递包含要绑定的所有必要数据的上下文。

例如:在上面的例子中,如果您看到我们通过let-item声明了item变量,但item来自哪里。这将由给定给*ngTemplateOutlet的上下文来决定。

一行结论如果我们想注入将来将由某人声明的模板,我无法通过*ngIf或*ngSwitch处理这种情况。我们需要使用*ngTemplateOutlet

当您需要处理嵌套项目时,可以看到ngTemplateOutlet的真正威力,因为您不知道可以达到多少级别。在处理嵌套数组时,执行ngFor或ngSwitch是很麻烦的,而且是有限的,因为你总是需要事先知道你想要深入多少层:

例如:

如果这是我的阵列:

todo = [
'Get to work',
[
'Get up',
'Brush teeth',
'Take a shower',
'Check e-mail',
'Walk dog'
],
[
'Prepare for work',
'Drive to office',
'Park car',
'Work',
[
'See Clients',
'Fill Out Forms',
'Take Tea Breaks',
[
'Switch on Kettle',
'Get Clean Cup',
'Add Tea',
'Pour Water',
'Drink'
]
]
],
'Pick up groceries',
'Go home',
'Fall asleep'
];

然后你可以使用以下方法:

<div *ngFor="let item of todo" style="margin-left: 25px">
<div *ngIf="!isArray(item); else arrayView">{{item}}</div>
<ng-template #arrayView>
<div *ngFor="let item2 of item" style="margin-left: 25px">
<p>And So On...</p>
</div>
</ng-template>
</div>

但是,如果你不知道你的阵列有多少层深呢?您可以将ngTemplateOutlet与ng模板结合使用来解决问题:

<ng-template #tmplItems let-todo="todo">
<div *ngFor="let item of todo" style="margin-left: 25px">
<div *ngIf="!isArray(item); else arrayView">{{item}}</div>
<ng-template #arrayView>
<ng-container *ngTemplateOutlet="tmplItems,context:{todo:item}">
</ng-container>
</ng-template>
</div>
</ng-template>
<div *ngFor="let item of todo">
<div *ngIf="!isArray(item); else arrayView">{{item}}</div>
<ng-template #arrayView>
<ng-container *ngTemplateOutlet="tmplItems,context:{todo:item}">
</ng-container>
</ng-template>
</div>

现在,不管你的数组深入多少层,递归地调用ng模板都可以解决这个问题(除非有我还不知道的限制)。

输出:

Get to work
Get up
Brush teeth
Take a shower
Check e-mail
Walk dog
Prepare for work
Drive to office
Park car
Work
See Clients
Fill Out Forms
Take Tea Breaks
Switch on Kettle
Get Clean Cup
Add Tea
Pour Water
Drink
Pick up groceries
Go home
Fall asleep

相关内容

  • 没有找到相关文章

最新更新