我在“材质对话框”组件中具有“角度”形式。有双向绑定的数据,当在输入中切换或键入输入时,屏幕在两次按下之间会锁定几秒钟。所有数据都可以正常传递,但是在尝试使用表单时速度很慢。
我尝试重构该表单以用于输入,以使用“材料表单”,但仍然具有相同的减速性能。
我的配置有问题吗?还是在最新的Angular 8动画/ CDK包中可能会回归?这是我的Angular软件包依赖项:
dependencies": {
"@angular/animations": "^8.2.13",
"@angular/cdk": "^8.2.3",
"@angular/common": "~8.2.13",
"@angular/compiler": "~8.2.13",
"@angular/core": "~8.2.13",
"@angular/forms": "~8.2.13",
"@angular/material": "^8.2.3",
"@angular/platform-browser": "~8.2.13",
"@angular/platform-browser-dynamic": "~8.2.13",
"@angular/router": "~8.2.13",
}
这是调用对话框的组件方法:
public editRow(tablerow: IRule): void {
const dialogRef = this.dialog.open(EditDialogComponent, {
width: '100%',
height: '85%',
data: tablerow
});
this.subscriptions.push(
dialogRef.afterClosed().subscribe(updatedRule => {
if (updatedRule !== undefined) {
this.rules = this.rules.map(rule => rule.Id === updatedRule.Id ? updatedRule : rule);
this.subscriptions.push(this.dataService.updateRule(updatedRule).subscribe(
response => {
this.snackBar.openFromComponent(SuccessComponent, {
duration: 3000,
data: `Rule added`
});
}, error => {
this.snackBar.openFromComponent(ErrorComponent, {
duration: 10000,
data: 'Internal Server Error'
});
}
));
}
})
);
}
包含以下形式的mat对话框模板:
<mat-dialog-content>
<i id="close-icon" class="material-icons md-24" aria-label="close"
[mat-dialog-close]>close</i>
<div class="brand-panel-container">
<div class="brand-panel">
<div class="brand-panel-header">
<div class="brand-title">
<h4 mat-dialog-title>Rule: {{ data.Id }}</h4>
</div>
</div>
<form #ruleForm="ngForm">
<div class="row">
<div class="col-md-6">
<div class="form-group">
<label for="name">Shop Type:<span class="asterisk">*</span></label>
<select
[(ngModel)]="data.Type.Text"
value="{{ data.Type.Text }}"
name="type"
type="text"
class="form-control"
id="type"
required>
<option *ngFor="let opt of shopTypeOpts; trackBy: indentify" value="{{opt.Text}}">{{opt.Text}}</option>
</select>
</div>
</div>
<div class="col-md-6">
<div class="form-group">
<label for="name">Origin:<span class="asterisk">*</span></label>
<input
[(ngModel)]="data.Origin"
value="{{ data.Origin }}"
name="origin"
type="text"
class="form-control"
id="origin"
required>
</div>
</div>
</div>
<div class="row">
<div class="col-md-6">
<div class="form-group">
<label for="name">Destination:<span class="asterisk">*</span></label>
<input
[(ngModel)]="data.Destination"
value="{{ data.Destination }}"
name="destination"
type="text"
class="form-control"
id="destination"
required>
</div>
</div>
<div class="col-md-6">
<div class="form-group">
<label for="name">Fare:<span class="asterisk">*</span></label>
<input
[(ngModel)]="data.Fare.Text"
value="{{ data.Fare.Text }}"
name="fare"
type="text"
class="form-control"
id="fare"
required>
</div>
</div>
</div>
<div class="row">
<div class="col-md-6">
<div class="form-group">
<label for="name">Government:<span class="asterisk">*</span></label>
<select
[(ngModel)]="data.Government.Text"
value="{{ data.Government.Text }}"
name="government"
type="text"
class="form-control"
id="government"
required>
<option *ngFor="let opt of governmentTypeOpts; trackBy: indentify"
value="{{opt.Text}}">{{opt.Text}}</option>
</select>
</div>
</div>
<div class="col-md-6">
<div class="form-group">
<label for="name">Special Pricing:<span class="asterisk">*</span></label>
<select
[(ngModel)]="data.SpecialPricing.Text"
value="{{ data.SpecialPricing.Text }}"
name="specialPricing"
type="text"
class="form-control"
id="specialPricing"
required>
<option *ngFor="let opt of specialPricingTypeOpts; trackBy: indentify"
value="{{opt.Text}}">{{opt.Text}}</option>
</select>
</div>
</div>
</div>
<div class="row">
<div class="col-md-6">
<div class="form-group">
<label for="name">Upgrade:<span class="asterisk">*</span></label>
<select
[(ngModel)]="data.Upgrade.Text"
value="{{ data.Upgrade.Text }}"
name="upgrade"
type="text"
class="form-control"
id="upgrade"
required>
<option *ngFor="let opt of upgradeTypeOpts; trackBy: indentify"
value="{{opt.Text}}">{{opt.Text}}</option>
</select>
</div>
</div>
<div class="col-md-6">
<div class="form-group">
<label for="name">Cabin Count:<span class="asterisk">*</span></label>
<input
[(ngModel)]="data.CabinCount"
value="{{ data.CabinCount }}"
name="cabinCount"
type="text"
class="form-control"
id="cabinCount"
required>
</div>
</div>
</div>
<div class="row">
<div class="col-md-6">
<div class="form-group">
<label for="name">Columns Count:<span class="asterisk">*</span></label>
<input
[(ngModel)]="data.ColumnsCount"
value="{{ data.ColumnsCount }}"
name="columnsCount"
type="text"
class="form-control"
id="columnsCount"
required>
</div>
</div>
<div class="col-md-6">
<div class="form-group">
<label for="name">Lang Code:<span class="asterisk">*</span></label>
<input
[(ngModel)]="data.LangCode"
value="{{ data.LangCode }}"
name="langCode"
type="text"
class="form-control"
id="langCode"
required>
</div>
</div>
</div>
<div class="row">
<div class="col-md-6">
<div class="form-group">
<label for="name">Fare Wheel Search?:<span class="asterisk">*</span></label>
<input
[(ngModel)]="data.IsFareWheelSearch"
value="{{ data.IsFareWheelSearch }}"
name="isFareWheelSearch"
type="text"
class="form-control"
id="isFareWheelSearch"
required>
</div>
</div>
<div class="col-md-6">
<div class="form-group">
<label for="name">Markets:<span class="asterisk">*</span></label>
<select
[(ngModel)]="data.Markets.Text"
value="{{ data.Markets.Text }}"
name="markets"
type="text"
class="form-control"
id="markets"
required>
<option *ngFor="let opt of marketTypeOpts; trackBy: indentify" value="{{opt.Text}}">{{opt.Text}}</option>
</select>
</div>
</div>
</div>
<div class="row">
<div class="col-md-6">
<div class="form-group">
<label for="name">POS:<span class="asterisk">*</span></label>
<input
[(ngModel)]="data.POS"
value="{{ data.POS }}"
name="pos"
type="text"
class="form-control"
id="pos"
required>
</div>
</div>
<div class="col-md-6">
<div class="form-group">
<label for="name">Columns:<span class="asterisk">*</span></label>
<input
[(ngModel)]="data.Columns"
value="{{ data.Columns }}"
name="columns"
type="text"
class="form-control"
id="columns"
required>
</div>
</div>
</div>
<div mat-dialog-actions>
<span *ngIf="!ruleForm.valid" class="invalid-msg"><span
class="asterisk">*</span>All fields must be filled in to save
changes.</span>
<button mat-button class="brand-default-button"
[mat-dialog-close]>Cancel</button>
<button mat-button class="brand-confirm-button" type="submit"
[disabled]="!ruleForm.valid" [mat-dialog-close]="data.Id"
(click)="onSaveData(ruleForm.value)">Save Changes</button>
</div>
</form>
</div>
对话框组件文件:
import { Component, Inject } from '@angular/core';
import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog';
import { IRule } from '../../../models/rule.interface';
import { OptionsService } from 'src/app/shared/services/options.service';
import { IDropdownOption } from 'src/models/dropdown-option.interface';
@Component({
selector: 'app-edit-dialog',
templateUrl: './edit-dialog.component.html',
styleUrls: ['./edit-dialog.component.scss']
})
export class EditDialogComponent {
public shopTypeOpts: IDropdownOption[] = [];
public governmentTypeOpts: IDropdownOption[] = [];
public specialPricingTypeOpts: IDropdownOption[] = [];
public fareTypeOpts: IDropdownOption[] = [];
public upgradeTypeOpts: IDropdownOption[] = [];
public marketTypeOpts: IDropdownOption[] = [];
constructor(
public dialogRef: MatDialogRef<EditDialogComponent>,
public optionsService: OptionsService,
@Inject(MAT_DIALOG_DATA) public data: IRule) {
this.shopTypeOpts = this.optionsService.shopTypeOptions;
this.governmentTypeOpts = this.optionsService.governmentTypeOptions;
this.specialPricingTypeOpts = this.optionsService.specialPricingTypeOptions;
this.fareTypeOpts = this.optionsService.fareTypeOptions;
this.upgradeTypeOpts = this.optionsService.upgradeTypeOptions;
this.marketTypeOpts = this.optionsService.marketTypeOptions;
}
public onSaveData(updatedRule: IRule): void {
this.dialogRef.close(updatedRule);
}
public indentify(index, item) {
return item.Text;
}
}
IDropdownOption接口:
export interface IDropdownOption {
Text: string;
Value: number;
}
*已编辑,其中包括trackBy函数和IDropdownOption接口,以查看唯一标识符。 *
速度下降似乎是因为下拉选项被反复循环了……也许changeDetection策略需要改变?
答案 0 :(得分:0)
我会回答,因为我想我知道是什么导致您的速度下降。除了trackBy
缺少*ngFor
方法之外,它还必须检查您每次输入的整个模板。建议使用OnPush
更改检测策略。这可能会使某些事情无法按您期望的方式工作,但这是使组件保持快速运行的好方法,因为只有在更改输入(和其他事情)后,才会检查更改。
在这个问题上,这仍然是不错的article。
您应该将对话框组件装饰器更改为包括OnPush
:
@Component({
selector: 'app-edit-dialog',
templateUrl: './edit-dialog.component.html',
styleUrls: ['./edit-dialog.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush
})
答案 1 :(得分:0)
非常感谢大家的帮助。我通过在父组件中使用ChangeDetectorRef来解决问题,方法是在打开对话框后将其分离,并在关闭对话框后重新附加。这样可以防止任何重新渲染/重新绘制EditDialogComponent并解决性能问题。
public editRow(tablerow: IRule): void {
this.changeDetectorRef.detach(); // Detach change detection before the dialog opens.
const dialogRef = this.dialog.open(EditDialogComponent, {
width: '100%',
height: '85%',
data: tablerow
});
this.subscriptions.push(
dialogRef.afterClosed().subscribe(updatedRule => {
this.changeDetectorRef.reattach(); // Reattach change detection after the dialog closes.
if (updatedRule !== undefined) {
this.rules = this.rules.map(rule => rule.Id === updatedRule.Id ? updatedRule : rule);
this.subscriptions.push(this.dataService.updateRule(updatedRule).subscribe(
response => {
this.snackBar.openFromComponent(SuccessComponent, {
duration: 3000,
data: `Rule added`
});
}, error => {
this.snackBar.openFromComponent(ErrorComponent, {
duration: 10000,
data: 'Internal Server Error'
});
}
));
}
})
);
}
答案 2 :(得分:0)
此答案取决于用例。 可能听起来很奇怪!
背景:我已经在我的自定义网格/表格组件中实现了 OnPush 策略以及分离重新附加的 ChangeDetectorRef,其中很少有元素在 renderer2 的帮助下使用指令添加了玻璃覆盖
我在打开对话框时添加了模糊背景作为“backdropClass”属性。
当屏幕尺寸更大时会导致延迟,如果我减小屏幕尺寸,它会表现良好。如果我从 Dom 树中删除几个元素,它会表现得很好。
所以我发现它是慢慢应用的背景类,导致整个对话滞后的错觉。
只需将其删除即可。
希望这能帮助那些对已经实施的所有解决方案感到头疼的人:)
this.dialog
.open(CreateKeyComponent, {
disableClose: true,
// backdropClass: 'blur', -----> root cause
position: { top: '15vh' },
data: {
data: this.tableDataShowFlag ? '1' : '0',
},
})