感谢 Günter Zöchbauer 的回答(见评论),我得到了它的工作。
据我了解,Angular 的变化检测器是这样工作的:
cd.detectChanges(); // Detects changes but doesn't update view.
cd.markForCheck(); // Marks view for check but doesn't detect changes.
因此,您需要同时使用两者才能快速重建整个组件树。
1.模板更改
为了重新加载整个应用程序,我们需要隐藏和显示所有组件树,因此我们需要将所有内容包装app.component.html
到ng-container
:
<ng-container *ngIf="!reloading">
<header></header>
<main>
<router-outlet></router-outlet>
</main>
<footer></footer>
</ng-container>
ng-container
比 div 好,因为它不渲染任何元素。
对于异步支持,我们可以这样做:
<ng-container *ngIf="!(reloading$ | async)"> ... </ng-container>
reloading: boolean
这里reloading$: Observable<boolean>
表示该组件当前正在重新加载。
在我有可观察的组件LocaleService
中language$
。我将监听更改的语言事件并执行应用程序重新加载操作。
2.同步示例
export class AppComponent implements OnInit {
reloading: boolean;
constructor(
private cd: ChangeDetectorRef,
private locale: LocaleService) {
this.reloading = false;
}
ngOnInit() {
this.locale.language$.subscribe(_ => {
this.reloading = true;
this.cd.detectChanges();
this.reloading = false;
this.cd.detectChanges();
this.cd.markForCheck();
});
}
}
3. 异步示例
export class AppComponent implements OnInit {
reloading: BehaviorSubject<boolean>;
get reloading$(): Observable<boolean> {
return this.reloading.asObservable();
}
constructor(
private cd: ChangeDetectorRef, // We still have to use it.
private locale: LocaleService) {
this.reloading = new BehaviorSubject<boolean>(false);
}
ngOnInit() {
this.locale.language$.subscribe(_ => {
this.reloading.next(true);
this.cd.detectChanges();
this.reloading.next(false);
this.cd.detectChanges();
});
}
}
我们现在不必这样做,cd.markForChanges()
但我们仍然必须告诉检测器来检测变化。
4.路由器
路由器无法按预期工作。以这种方式重新加载应用程序时,router-outlet
内容将变为空。我还没有解决这个问题,走同样的路可能会很痛苦,因为这意味着用户在表单中所做的任何更改都会被更改并丢失。
5. OnInit
您必须使用 OnInit 挂钩。如果你尝试在构造函数中调用 cd.detectChanges() ,你会得到一个错误,因为 angular 还不会构建组件,但你会尝试检测它的变化。
现在,您可能认为我在构造函数中订阅了另一个服务,并且我的订阅只有在组件完全初始化后才会触发。但问题是 - 你不知道服务是如何运作的!例如,如果它只是发出一个值Observable.of('en')
- 你会得到一个错误,因为一旦你订阅 - 第一个元素立即发出,而组件仍未初始化。
我LocaleService
也有同样的问题:observable 背后的主题是BehaviorSubject
. BehaviorSubject
是 rxjs 主题,在您订阅后立即发出默认值。因此,一旦您编写this.locale.language$.subscribe(...)
- 订阅立即触发至少一次,然后您将等待语言更改。