From bd97dbafb95771e4bbbcbbe6230dfde092b31f59 Mon Sep 17 00:00:00 2001 From: crisbeto Date: Tue, 1 Aug 2017 08:23:17 +0300 Subject: [PATCH] perf(sidenav): avoid recalculating the inline styles while sidenav is open * Avoids recalculating the sidenav inline styles for every change detection cycle while the sidenav is open by doing it only when an animation starts. * Removes a few one-liner methods that were being used in one place. --- src/lib/sidenav/sidenav-container.html | 2 +- src/lib/sidenav/sidenav.spec.ts | 2 +- src/lib/sidenav/sidenav.ts | 61 ++++++++++---------------- 3 files changed, 24 insertions(+), 41 deletions(-) diff --git a/src/lib/sidenav/sidenav-container.html b/src/lib/sidenav/sidenav-container.html index 24f0789dcde2..11c19f8c0c21 100644 --- a/src/lib/sidenav/sidenav-container.html +++ b/src/lib/sidenav/sidenav-container.html @@ -3,6 +3,6 @@ -
+
diff --git a/src/lib/sidenav/sidenav.spec.ts b/src/lib/sidenav/sidenav.spec.ts index ee2bf7ce5405..7c9d10e6fb97 100644 --- a/src/lib/sidenav/sidenav.spec.ts +++ b/src/lib/sidenav/sidenav.spec.ts @@ -350,7 +350,7 @@ describe('MdSidenavContainer', () => { const contentElement = fixture.debugElement.nativeElement.querySelector('.mat-sidenav-content'); - expect(parseInt(contentElement.style.marginLeft)).toBe(0); + expect(parseInt(contentElement.style.marginLeft)).toBeFalsy(); fixture.componentInstance.showSidenav = true; fixture.detectChanges(); diff --git a/src/lib/sidenav/sidenav.ts b/src/lib/sidenav/sidenav.ts index 47eb18bf7724..c051a8202f01 100644 --- a/src/lib/sidenav/sidenav.ts +++ b/src/lib/sidenav/sidenav.ts @@ -326,6 +326,9 @@ export class MdSidenavContainer implements AfterContentInit { private _left: MdSidenav | null; private _right: MdSidenav | null; + /** Inline styles to be applied to the container. */ + _styles: { marginLeft: string; marginRight: string; transform: string; }; + constructor(@Optional() private _dir: Directionality, private _element: ElementRef, private _renderer: Renderer2, private _ngZone: NgZone, private _changeDetectorRef: ChangeDetectorRef) { @@ -362,13 +365,13 @@ export class MdSidenavContainer implements AfterContentInit { * is properly hidden. */ private _watchSidenavToggle(sidenav: MdSidenav): void { - takeUntil.call(sidenav._animationStarted, this._sidenavs.changes) - .subscribe(() => { - // Set the transition class on the container so that the animations occur. This should not - // be set initially because animations should only be triggered via a change in state. - this._renderer.addClass(this._element.nativeElement, 'mat-sidenav-transition'); - this._changeDetectorRef.markForCheck(); - }); + takeUntil.call(sidenav._animationStarted, this._sidenavs.changes).subscribe(() => { + // Set the transition class on the container so that the animations occur. This should not + // be set initially because animations should only be triggered via a change in state. + this._renderer.addClass(this._element.nativeElement, 'mat-sidenav-transition'); + this._updateStyles(); + this._changeDetectorRef.markForCheck(); + }); if (sidenav.mode !== 'side') { takeUntil.call(merge(sidenav.onOpen, sidenav.onClose), this._sidenavs.changes).subscribe(() => @@ -461,40 +464,20 @@ export class MdSidenavContainer implements AfterContentInit { return (this._isSidenavOpen(sidenav) && sidenav.mode == mode) ? sidenav._width : 0; } - _getMarginLeft() { - return this._left ? this._getSidenavEffectiveWidth(this._left, 'side') : 0; - } - - _getMarginRight() { - return this._right ? this._getSidenavEffectiveWidth(this._right, 'side') : 0; - } - - _getPositionLeft() { - return this._left ? this._getSidenavEffectiveWidth(this._left, 'push') : 0; - } - - _getPositionRight() { - return this._right ? this._getSidenavEffectiveWidth(this._right, 'push') : 0; - } - - /** - * Returns the horizontal offset for the content area. There should never be a value for both - * left and right, so by subtracting the right value from the left value, we should always get - * the appropriate offset. - */ - _getPositionOffset() { - return this._getPositionLeft() - this._getPositionRight(); - } - /** - * This is using [ngStyle] rather than separate [style...] properties because [style.transform] - * doesn't seem to work right now. + * Recalculates and updates the inline styles. Note that this + * should be used sparingly, because it causes a reflow. */ - _getStyles() { - return { - marginLeft: `${this._getMarginLeft()}px`, - marginRight: `${this._getMarginRight()}px`, - transform: `translate3d(${this._getPositionOffset()}px, 0, 0)` + private _updateStyles() { + const marginLeft = this._left ? this._getSidenavEffectiveWidth(this._left, 'side') : 0; + const marginRight = this._right ? this._getSidenavEffectiveWidth(this._right, 'side') : 0; + const leftWidth = this._left ? this._getSidenavEffectiveWidth(this._left, 'push') : 0; + const rightWidth = this._right ? this._getSidenavEffectiveWidth(this._right, 'push') : 0; + + this._styles = { + marginLeft: `${marginLeft}px`, + marginRight: `${marginRight}px`, + transform: `translate3d(${leftWidth - rightWidth}px, 0, 0)` }; } }