渲染发生在变更检测之后。要强制进行变更检测,以便将已更改的组件属性值传播到DOM(然后浏览器将在视图中呈现这些更改),以下是一些选项:
$rootScope.$digest()
-- 即检查整个组件树$rootScope.$apply(callback)
-- 即在 Angular 2 区域内评估回调函数。我认为,但不确定,这最终会在执行回调函数后检查整个组件树。$scope.$digest()
-- 即仅检查此组件及其子级您需要导入并注入ApplicationRef
、NgZone
或ChangeDetectorRef
到您的组件中。
对于您的特定情况,如果只有一个组件发生了更改,我建议使用最后一个选项。
this
上下文。 - Mark Rajcokpure:false
。它可以工作,但对于我的用例来说太昂贵(低效)了。 - Natetx,我找到了我需要的解决方法:
constructor(private zone:NgZone) {
// enable to for time travel
this.appStore.subscribe((state) => {
this.zone.run(() => {
console.log('enabled time travel');
});
});
运行 zone.run 将强制组件重新渲染。
变更检测器参考方法
import { Component, OnInit, ChangeDetectorRef } from '@angular/core';
export class MyComponent {
constructor(private cdr: ChangeDetectorRef) { }
selected(item: any) {
if (item == 'Department')
this.isDepartment = true;
else
this.isDepartment = false;
this.cdr.detectChanges();
}
}
我使用 *ngIf 强制重新加载我的组件。
容器内的所有组件都会重新经历完整的生命周期钩子。
在模板中:
<ng-container *ngIf="_reload">
components here
</ng-container>
然后在 ts 文件中:
public _reload = true;
private reload() {
setTimeout(() => this._reload = false);
setTimeout(() => this._reload = true);
}
setTimeout()
之外的所有内容。 现在我的问题通过简单而轻巧的解决方案得到了解决! - LHM这里的其他答案提供了触发变化检测周期以更新组件视图的解决方案(这与完全重新渲染不同)。
完全重新渲染可以通过以下方式使用ng-template
、ng-container
和ViewContainerRef
实现,从而销毁并重新初始化组件(调用所有生命周期钩子并重建视图):
<div>
<ng-container #outlet >
</ng-container>
</div>
<ng-template #content>
<child></child>
</ng-template>
那么,在引用#outlet
和#content
的组件中,我们可以清除插座内容并插入另一个子组件实例:
@ViewChild("outlet", {read: ViewContainerRef}) outletRef: ViewContainerRef;
@ViewChild("content", {read: TemplateRef}) contentRef: TemplateRef<any>;
private rerender() {
this.outletRef.clear();
this.outletRef.createEmbeddedView(this.contentRef);
}
此外,初始内容应在AfterContentInit
钩子上插入:
ngAfterContentInit() {
this.outletRef.createEmbeddedView(this.contentRef);
}
可以在这里找到完整的工作解决方案 https://stackblitz.com/edit/angular-component-rerender。
ngAfterViewInit
。
顺便说一句,当输入保留了先前的值而表单模型是正确的时候,这是唯一有效的解决方案。这发生在我在通过 :id
路由区分的路由之间切换时。
最后,我不得不在每次导航结束时调用 rerender
函数。 - Marcin WojtachChangeDetectorRef.detectChanges()
一般是最专注的方法。ApplicationRef.tick()
则通常过于粗暴。
要使用ChangeDetectorRef.detectChanges()
,您需要在组件顶部添加以下代码:
import { ChangeDetectorRef } from '@angular/core';
通常情况下,你会在构造函数中使用别名来注入它,像这样:
constructor( private cdr: ChangeDetectorRef ) { ... }
然后,在适当的位置调用它,像这样:
this.cdr.detectChanges();
ChangeDetectorRef.detectChanges()的调用位置非常重要,与应用程序组件的生命周期和呈现方式密切相关。在此处,完全了解Angular生命周期是必不可少的,没有什么替代方法。确保你理解内部细节后,就可以适当地使用ChangeDetectorRef.detectChanges()(有时很容易理解何时使用它,但有时可能会非常复杂)。