Angular2可观察变化检测模板更新

时间:2016-05-27 08:14:51

标签: angular observable angular2-changedetection

出于性能原因,我正在尝试在我的组件上设置手动更改检测。

app的结构:App - >书籍 - >网页

我在AppComponent中订阅了一个observable,然后运行" markForCheck" ChangeDetectorRef的方法。

这似乎触发了BookComponent中的ngAfterContentChecked方法(我标记为更新的组件的子组件)。

这让我相信" markForCheck"在父组件中也会更新所有子组件。

但是,即使在子(BookComponent)中执行了ngAfterContentChecked,该组件的模板也不会更新!

我是否应该倾听每个孩子中的观察者(有时在组件层次结构中有几个层次)?或者我做错了什么?为什么ngAfterContentChecked在子组件中执行,即使模板没有更新?

一些相关的代码。

@Component({
    selector: 'app',
    directives: [BookComponent],
    changeDetection: ChangeDetectionStrategy.OnPush,
    template: `
        <book *ngIf="_book" [book]="_book" [style.height]="_availableDimensions.height+'px'" (window:resize)="onResize($event)"></book>
        <footer id="footer"></footer>
    `
})

export class PlayerComponent {
    ngOnInit() {
        this.initScale();
    }

initScale(){
        this._playerService.availableDimensions$.subscribe(
            availableDimensions => {
                // set local availableDimensions variable
                this._availableDimensions = availableDimensions;
                this._cd.markForCheck();
            }
        );
    }
}



@Component({
    selector: 'book',
    directives: [PageComponent],
    changeDetection: ChangeDetectionStrategy.OnPush,
    template: `
        <div id="pageScrollZone">
            <div id="pageHolder" [ngStyle]="pageHolderStyles()"></div>
        </div>
    `
})

export class BookComponent {
    constructor(
            private _cd: ChangeDetectorRef,
            private _playerService: PlayerService,
            private _config: Config
    ){}

    ngAfterContentChecked(){
// This part does execute when the observable changes
        let date = new Date();
        console.log('BOOK: '+date.getHours()+':'+date.getMinutes()+':'+date.getSeconds());
    }

    pageHolderStyles(){
// This part does NOT execute when the observable changes
        let styles = {
            marginTop: this._currentMargin.y+'px',
            transform: 'scale('+ (this._baseZoom * this._currentZoomLevel) +')'
        }

        return styles;
    }
}

1 个答案:

答案 0 :(得分:2)

Sooo ......两件快事......

首先,当您使用markForCheck()时,它会在组件 ITSELF ROOT COMPONENT 之间进行标记,以标记Angular应运行更改检测的路径。

From a great Thoughtram Article: tree

  

&#34;我们可以通过依赖访问组件的ChangeDetectorRef   注入,它带有一个名为markForCheck()的API。这种方法   完全符合我们的需要!它标志着我们组件的路径   要检查下一次更改检测运行的根。&#34;

因此,当您触发它并不会查看它自己的孩子时,它会看向根组件。如果它的孩子也在推动,他们会忽略它的更新。

  

我是否应该倾听每个孩子的观察点(有时在组件层次结构中有几个层次)?

仅当您希望所有元素都明确地为onPush时。 我猜你想要页面自动更新,如果它的父母确实...那么你很幸运!如果您在网页组件上使用标准策略,并在图书上使用 onPush策略,当检测结果在树上运行时, SKIP 那个分支,即使孩子是正常的组成部分。 Source:Victor Savkin

所以你不必深深地倾听观察者,只要你想要休息的地方。 如果你不得不欺骗它,那么每个正在onPush的组件都不能保证性能提升。在大多数情况下,仅阻止关键节点就足够了。

第二件事是关于 ngAfterContentChecked 这是一个已知的错误:

(完全相同)https://github.com/angular/angular/issues/7055

(相关,更好地讨论两者)https://github.com/angular/angular/issues/7054

所以他们知道它,它实际上并没有运行检测,但是它会触发回调......