【发布时间】:2026-02-16 07:50:01
【问题描述】:
在我的组件中,我得到一个 Observable 作为 @Input()。
如果 Observable 的值发生变化,我必须展开/折叠 ng-bootstrap 手风琴。所以我真的不需要模板中的 Observable 的值。
这是代码,我已经有了:
组件:
@Input() urlParam$!: Observable<string>;
@ViewChild('acc') accordion!: NgbAccordion;
urlParamChange$!: Observable<string>;
ngAfterViewInit(): void {
this.urlParamChange$ = this.urlParam$.pipe(
tap(urlParam => this.synchronizeAccordion(urlParam))
);
}
synchronizeAccordion(urlParam: string): void {
// do something with this.accordion
}
在模板中,我通过异步管道订阅了新创建的 urlParamChange$:
<ng-container *ngIf="(urlParamChange$ | async)"></ng-container>
<ngb-accordion #acc="ngbAccordion">
....
</ngb-accordion>
由于我真的不需要urlParamChange$的值,所以我把它放在一个自己的ng-container中,这样完全独立,但是仍然会调用同步手风琴的方法。
我认为,上面的实现并不是那么好。您将操作拆分为两个不同的文件(需要组件中的 tap + 模板中的异步管道)。
下面的方式不是更好吗? 我不会在异步管道的帮助下订阅,而是直接在 ngAfterViewInit() 中订阅()。这样我就可以删除额外的变量 urlParamChange$ 并且实现全部在 ngAfterViewInit() 方法中。
组件:
@Input() urlParam$!: Observable<string>;
@ViewChild('acc') accordion!: NgbAccordion;
ngAfterViewInit(): void {
this.urlParam$.subscribe(urlParam => this.synchronizeAccordion(urlParam));
}
synchronizeAccordion(urlParam: string): void {
// do something with this.accordion
}
并且在模板中额外的 ng-container 被移除:
<ngb-accordion #acc="ngbAccordion">
....
</ngb-accordion>
在我看来,两种实现都应该以完全相同的方式工作。根据最佳实践,我认为应该首选第一个解决方案。但第二个是更清洁的 IMO。
那么实现这种用例的最佳方式是什么?
【问题讨论】:
-
我认为你是对的。有人告诉过你要另辟蹊径吗?
-
不,我现在没有那么多经验,所以我不确定该使用哪一个。那么解决方案 #1 是首选方式吗?
-
可以像我一样使用“虚拟 ng-container”吗?哪个没有实际意义,只能通过异步管道订阅 observable?
-
我指的是第二个,你认为更干净的那个。使用异步管道是“最佳实践”的唯一原因是您不必手动取消订阅,因此它通常会变得更干净。但是,如果像您的情况一样,它不能使它更干净,您可能应该使用手动订阅/取消订阅实现。什么是“最佳实践”,什么不是“最佳实践”始终是一种意见,没有什么可以虔诚地遵循。了解最佳实践背后的原因,如果它对您的情况没有意义,请不要遵循它。
标签: angular typescript rxjs