背景: 我有一个 Angular 的 LoginFormComponent 。在此组件中,我有一个包含 2 个属性的表单:电子邮件和密码。我想要实现的是在这个组件中创建我可以在模板中访问的属性,这样我就可以做这样的事情
*ngIf="emailIsInvalid && emailIsDirty"
,而不必做类似emailControl?.value === ''
的事情。
目前我的组件中存在很多属性:
emailIsEmpty: boolean | undefined;
emailIsDirty: boolean | undefined;
emailIsInvalid: boolean | undefined;
emailValue: string | undefined;
passwordIsEmpty: boolean | undefined;
passwordIsDirty: boolean | undefined;
passwordIsInvalid: boolean | undefined;
passwordValue: string | undefined;
emailOrPasswordHasErrors: boolean | undefined;
如果有变化我会更新:
ngOnInit(): void {
this.formGroup.valueChanges.subscribe(() => {
this.updateEmailAfterChanges();
this.updatePasswordAfterChanges();
});
}
updateEmailAfterChanges(): void {
this.emailIsEmpty = this.emailControl?.value === '';
this.emailIsDirty = this.emailControl?.dirty ?? false;
this.emailIsInvalid = this.emailControl?.invalid ?? false;
this.emailValue = this.emailControl?.value ?? '';
this.emailOrPasswordHasErrors =
this.emailIsInvalid || this.emailIsEmpty || this.passwordIsInvalid || this.passwordIsEmpty;
}
updatePasswordAfterChanges(): void {
this.passwordIsEmpty = this.passwordControl?.value === '';
this.passwordIsDirty = this.passwordControl?.dirty ?? false;
this.passwordIsInvalid = this.passwordControl?.invalid ?? false;
this.emailOrPasswordHasErrors =
this.emailIsInvalid || this.emailIsEmpty || this.passwordIsInvalid || this.passwordIsEmpty;
this.passwordValue = this.passwordControl?.value ?? '';
}
据我了解,像这样解决这个问题将是一个性能问题:
get emailIsDirty(): boolean {
return this.emailControl?.value === '';
}
请帮助我找到一个解决方案,帮助我保持组件精简并让我在模板中执行表示逻辑,但模板中也没有不可读的代码检查表单控件本身。
使用 getter 或函数调用模板 - 正如您正确提到的 - 在性能方面可能是一种不好的做法,特别是如果组件具有默认的更改检测策略并且其模板包含大量业务逻辑!
可能会出现不需要的变更检测周期,有时会导致用户体验滞后。
如果处理得当,可观察量将能够让你的生活更轻松(一旦熟悉了它,当然😉),并且会让你的应用程序更加高效。
我要做的如下。我会创建一些像这样的派生可观察量,并使用
AsyncPipe
将它们使用到模板中 - 因此确保它们安全地取消订阅。
此外,我会选择changeDetectionStrategy OnPush,以便进行更细粒度的更改检测,并仅在每个订阅的可观察量发送到模板中时重新渲染(比“标准”方式有更多的控制!)。
email$ = this.emailConfrol.valueChanges.pipe(
distinctUntilChanged()
);
isEmailValid$ = this.emailControl.statusChanges.pipe(
map((status) => status === 'VALID')
);
此外,有时您可能还需要订阅
.ts
,特别是当您的表单组件具有复杂的业务逻辑时。在这种情况下,我建议始终使用 takeUntil-destroy$ 作为最后一个管道运算符,以避免内存泄漏和性能问题。
您可以找到很多有关此主题的指南。 (即这里)