角度材质对话框速度缓慢,且呈现和绑定损坏

问题描述 投票:0回答:1

我有一个使用 Angular Material 和 Angular Monaco 编辑器 v2 的 Angular 17 应用程序。请在 Stackblitz 上找到完整的重现。

repro 应用程序有一个绑定到 CTRL+P 的 Monaco 编辑器。当您按下此热键时,会弹出一个对话框,将

HelloComponent
包含在同一项目中。这是一个带有单个文本框输入的虚拟组件,您可以在其中输入名称。

问题是,当打开对话框时,其呈现会出现某种程度的延迟,直到材质样式不出现,并且绑定速度太慢以至于会中断。

我尝试使用分离更改检测并在对话框关闭后重新附加它,如建议的here,但没有任何变化。此外,对话框内的组件非常简单,因此不存在固有的性能问题。

重现项目描述

为了使名称输入组件既可用作“普通”组件又可用作材质对话框中包装的组件,它在其构造函数中为

MatDialogRef
进行可选注入(因此它可以关闭传递回数据的对话框)和可选数据通过令牌注入接收
MAT_DIALOG_DATA

Data 的类型为

HelloData
,仅包含字符串
name
属性。弹出窗口应显示收到的名称(如果有),并让您对其进行编辑。当您单击它时,它将返回新名称。

在容器组件方面,通过调用

insertText
,在底层 Monaco 实例上按按键绑定 CTRL+P 打开对话框。这会从摩纳哥获取当前选定的文本,并打开对话框,将此文本作为可编辑名称传递给它。

单击“确定”关闭对话框后,容器组件将负责用新名称(如果有)替换选择。

这是完整的组件模板:

<div>
  <form [formGroup]="form" (submit)="save()">
    <mat-form-field>
      <input
        type="text"
        matInput
        [formControl]="inputName"
        placeholder="name"
      />
    </mat-form-field>
    <p>Hello, {{ inputName.value }}!</p>
    <button mat-flat-button type="submit">OK</button>
  </form>
</div>

及其对应代码:

export interface HelloData {
  name?: string;
}

@Component({
  selector: 'app-hello',
  standalone: true,
  imports: [
    CommonModule,
    FormsModule,
    ReactiveFormsModule,
    MatButtonModule,
    MatFormFieldModule,
    MatDialogModule,
    MatInputModule,
  ],
  templateUrl: './hello.component.html',
  styleUrl: './hello.component.css',
})
export class HelloComponent {
  public inputName: FormControl<string | null>;
  public form: FormGroup;

  constructor(
    formBuilder: FormBuilder,
    @Optional()
    public dialogRef?: MatDialogRef<HelloComponent>,
    @Optional()
    @Inject(MAT_DIALOG_DATA)
    public data?: HelloData
  ) {
    this.inputName = formBuilder.control(data?.name || null);
    this.form = formBuilder.group({
      name: this.inputName,
    });
  }

  public save(): void {
    this.dialogRef?.close(this.inputName.value);
  }
}

最后,这是对话框的打开和关闭方式:

private async promptName(name?: string): Promise<string | undefined> {
  this._cd.detach();
  const dialogRef = this._dialog.open(HelloComponent, {
    data: {
      name,
    },
  });
  const result: HelloData | undefined = await firstValueFrom(
    dialogRef.afterClosed()
  );
  this._cd.reattach();
  this._cd.detectChanges();
  return result?.name;
}
angular angular-material monaco-editor
1个回答
0
投票

看起来摩纳哥执行的命令是在 NgZone 之外处理的,因此它根本不会触发更改检测。由于它位于区域之外,因此手动检查

ChangeDetectorRef
上的更改也不会产生任何结果。这会导致纯 html 被推送到 DOM,而没有由更改检测触发的其他内容。

您应该将命令句柄包含在

ngZone.run
中。注入区域:

constructor(private _dialog: MatDialog, private ngZone: NgZone) {}

然后将处理程序包装在

ngZone.run
中:

this._editor.addCommand(
  monaco.KeyMod.CtrlCmd | monaco.KeyCode.KeyP,
  async () => {
    this.ngZone.run(async () => await this.insertText());
  }
);

这是您的 stackblitz 的工作分支

总而言之,我假设如果您使用 monaco 的 Angular 包装器,它应该处理此类内容,因此您可能应该在相关的 git 存储库中创建一个问题。

© www.soinside.com 2019 - 2024. All rights reserved.