有什么更好的方法可以避免在 Angular 模板中使用方法调用?
What are better ways to avoid using method calls within Angular Templates?
我试图避免在 Angular 模板中使用方法调用,因为它们在那里性能不佳。假设我有一个名字列表:
const names: string[] = ['Billy', 'Mandy', 'Carl', 'Sheryl']
在我的模板中,我使用 ngFor 迭代列表并打印名称:
<ng-container *ngFor="let name of names">
<p>{{ name }}</p>
</ng-container>
但现在我只需要显示以 'S' 开头的名称,所以我更改为:
<ng-container *ngFor="let name of names">
<p *ngIf="doesNameStartWithS(name)">{{ name }}</p>
</ng-container>
现在我的模板中有一个方法,我知道它会比需要的次数多 运行 次。为了避免这种情况,我可以这样做:
// this runs whenever the names list changes
const nameStartsWithSList: boolean[] = this.names.map((name: string): boolean => this.doesNameStartWithS(name));
然后将我的模板更改为:
<ng-container *ngFor="let name of names; let i = index;">
<p *ngIf="nameStartsWithSList[i]">{{ name }}</p>
</ng-container>
但这引入了一个新的列表,完全避免了模板中的方法调用。有更好的方法吗?
这是一个非常有趣的问题。
一种可能的解决方案是将前缀和字段传递给指令并相应地对其进行操作。您可能会使用 renderer2 作为更好的解决方案来呈现带有您想要的字段的段落,但这只是为了展示它的工作原理。
@Input() chars: string;
@Input() field: string;
constructor(private el: ElementRef) {}
ngOnInit() {
if (this.field.toLowerCase().includes(this.chars.toLowerCase())) {
(this.el.nativeElement as HTMLElement).innerHTML = `<p>${this.field}</p>`;
}
}
另一件事(我实际上刚刚意识到)是您也可以将指令用作组件。
<ng-container *ngFor="let name of names">
<showIfStartsWith chars="s" [field]="name"></showIfStartsWith>
</ng-container>
完整演示 here.
编辑:
找到了另一个不那么奇怪的解决方案,没有将指令用作组件。 Demo V2
编辑 2:
找到了另一个解决方案,使用指令作为结构指令,展示了如何将多个参数传递给它。 Demo V3
我认为最好的方法是在 ts 文件中操作列表。
如果您的起始列表是:
const names: string[] = ['Billy', 'Mandy', 'Carl', 'Sheryl']
像
一样设置
output(array, modifier) {
***modify array to return only starting with modifier letter***
return modifiedArray
}
modifier: string = 's'
const names: string[] = output(['Billy', 'Mandy', 'Carl', 'Sheryl'], modifier)
然后使用
<div *ngFor="let name of names"> ...
我想在这种情况下我会使用一个管道来转换或过滤给定的数据,就像这样:
第一-upper.pipe.ts
import { Pipe, PipeTransform } from '@angular/core';
@Pipe({
name: 'firstUpper',
})
export class FirstUpperPipe implements PipeTransform {
transform(value: string, letter: string): any {
if(value.startsWith(letter)){
return value;
}
}
}
毕竟在你的模板中你可以这样使用:
<ng-container *ngFor="let name of names">
<p>{{ name | firstUpper:'S' }}</p>
</ng-container>
如果您有 app.module.ts 声明部分,您应该在 pipes.module.ts 中导入此管道。
我试图避免在 Angular 模板中使用方法调用,因为它们在那里性能不佳。假设我有一个名字列表:
const names: string[] = ['Billy', 'Mandy', 'Carl', 'Sheryl']
在我的模板中,我使用 ngFor 迭代列表并打印名称:
<ng-container *ngFor="let name of names">
<p>{{ name }}</p>
</ng-container>
但现在我只需要显示以 'S' 开头的名称,所以我更改为:
<ng-container *ngFor="let name of names">
<p *ngIf="doesNameStartWithS(name)">{{ name }}</p>
</ng-container>
现在我的模板中有一个方法,我知道它会比需要的次数多 运行 次。为了避免这种情况,我可以这样做:
// this runs whenever the names list changes
const nameStartsWithSList: boolean[] = this.names.map((name: string): boolean => this.doesNameStartWithS(name));
然后将我的模板更改为:
<ng-container *ngFor="let name of names; let i = index;">
<p *ngIf="nameStartsWithSList[i]">{{ name }}</p>
</ng-container>
但这引入了一个新的列表,完全避免了模板中的方法调用。有更好的方法吗?
这是一个非常有趣的问题。
一种可能的解决方案是将前缀和字段传递给指令并相应地对其进行操作。您可能会使用 renderer2 作为更好的解决方案来呈现带有您想要的字段的段落,但这只是为了展示它的工作原理。
@Input() chars: string;
@Input() field: string;
constructor(private el: ElementRef) {}
ngOnInit() {
if (this.field.toLowerCase().includes(this.chars.toLowerCase())) {
(this.el.nativeElement as HTMLElement).innerHTML = `<p>${this.field}</p>`;
}
}
另一件事(我实际上刚刚意识到)是您也可以将指令用作组件。
<ng-container *ngFor="let name of names">
<showIfStartsWith chars="s" [field]="name"></showIfStartsWith>
</ng-container>
完整演示 here.
编辑: 找到了另一个不那么奇怪的解决方案,没有将指令用作组件。 Demo V2
编辑 2: 找到了另一个解决方案,使用指令作为结构指令,展示了如何将多个参数传递给它。 Demo V3
我认为最好的方法是在 ts 文件中操作列表。
如果您的起始列表是:
const names: string[] = ['Billy', 'Mandy', 'Carl', 'Sheryl']
像
一样设置output(array, modifier) {
***modify array to return only starting with modifier letter***
return modifiedArray
}
modifier: string = 's'
const names: string[] = output(['Billy', 'Mandy', 'Carl', 'Sheryl'], modifier)
然后使用
<div *ngFor="let name of names"> ...
我想在这种情况下我会使用一个管道来转换或过滤给定的数据,就像这样:
第一-upper.pipe.ts
import { Pipe, PipeTransform } from '@angular/core';
@Pipe({
name: 'firstUpper',
})
export class FirstUpperPipe implements PipeTransform {
transform(value: string, letter: string): any {
if(value.startsWith(letter)){
return value;
}
}
}
毕竟在你的模板中你可以这样使用:
<ng-container *ngFor="let name of names">
<p>{{ name | firstUpper:'S' }}</p>
</ng-container>
如果您有 app.module.ts 声明部分,您应该在 pipes.module.ts 中导入此管道。