From 907191bbc2b669cc41a6f426091cca2131808508 Mon Sep 17 00:00:00 2001 From: "Manu Mtz.-Almeida" Date: Mon, 28 Nov 2016 16:00:41 +0100 Subject: [PATCH] perf(tabs): improve tab switching response --- scripts/gulp/util.ts | 2 +- src/components/app/app.scss | 5 ++-- src/components/content/content.ts | 24 ++++++++++++++++++- src/components/tabs/tab.ts | 9 +++++++ src/components/tabs/tabs.ts | 11 --------- src/components/tabs/test/badges/app-module.ts | 1 + src/components/tabs/test/colors/app-module.ts | 1 + .../tabs/test/tab-bar-scenarios/app-module.ts | 1 + src/components/tap-click/tap-click.ts | 21 +++++++++++++++- src/util/util.ts | 8 +++++++ 10 files changed, 67 insertions(+), 16 deletions(-) diff --git a/scripts/gulp/util.ts b/scripts/gulp/util.ts index 409689b22e2..9bd5e6ac053 100644 --- a/scripts/gulp/util.ts +++ b/scripts/gulp/util.ts @@ -53,7 +53,7 @@ export function createTempTsConfig(includeGlob: string[], target: string, module } function removeDebugStatements() { - let replacer = new Replacer(['console.debug', 'assert']); + let replacer = new Replacer(['console.debug', 'assert', 'runInDev']); return through.obj(function (file, encoding, callback) { const content = file.contents.toString(); const cleanedJs = replacer.replace(content); diff --git a/src/components/app/app.scss b/src/components/app/app.scss index e6e08059d10..24a9e44d235 100644 --- a/src/components/app/app.scss +++ b/src/components/app/app.scss @@ -85,16 +85,17 @@ ion-tabs { } ion-tab { - transform: translateY(-200%); + display: none; } ion-tab.show-tab { - transform: translateY(0); + display: block; } ion-app, ion-nav, ion-tab, +ion-tabs, .app-root, .ion-page { contain: strict; diff --git a/src/components/content/content.ts b/src/components/content/content.ts index 030b9830c68..315c603e6be 100644 --- a/src/components/content/content.ts +++ b/src/components/content/content.ts @@ -132,6 +132,7 @@ export class Content extends Ion { _sbPadding: boolean; _fullscreen: boolean; _footerEle: HTMLElement; + _dirty: boolean = false; /* * @private @@ -472,7 +473,6 @@ export class Content extends Ion { /** * Tell the content to recalculate its dimensions. This should be called * after dynamically adding headers, footers, or tabs. - * */ resize() { nativeRaf(() => { @@ -486,6 +486,14 @@ export class Content extends Ion { * DOM READ */ readDimensions() { + let cachePaddingTop = this._paddingTop; + let cachePaddingRight = this._paddingRight; + let cachePaddingBottom = this._paddingBottom; + let cachePaddingLeft = this._paddingLeft; + let cacheHeaderHeight = this._headerHeight; + let cacheFooterHeight = this._footerHeight; + let cacheTabsPlacement = this._tabsPlacement; + this._paddingTop = 0; this._paddingRight = 0; this._paddingBottom = 0; @@ -542,6 +550,16 @@ export class Content extends Ion { ele = ele.parentElement; } + + this._dirty = ( + cachePaddingTop !== this._paddingTop || + cachePaddingBottom !== this._paddingBottom || + cachePaddingLeft !== this._paddingLeft || + cachePaddingRight !== this._paddingRight || + cacheHeaderHeight !== this._headerHeight || + cacheFooterHeight !== this._footerHeight || + cacheTabsPlacement !== this._tabsPlacement + ); } /** @@ -549,6 +567,10 @@ export class Content extends Ion { * DOM WRITE */ writeDimensions() { + if (!this._dirty) { + console.debug('Skipping writeDimenstions'); + return; + } let scrollEle = this._scrollEle as any; if (!scrollEle) { diff --git a/src/components/tabs/tab.ts b/src/components/tabs/tab.ts index 19d456e93e7..17065cb8b18 100644 --- a/src/components/tabs/tab.ts +++ b/src/components/tabs/tab.ts @@ -5,6 +5,7 @@ import { Config } from '../../config/config'; import { DeepLinker } from '../../navigation/deep-linker'; import { GestureController } from '../../gestures/gesture-controller'; import { isTrueProperty } from '../../util/util'; +import { nativeRaf } from '../../util/dom'; import { Keyboard } from '../../util/keyboard'; import { NavControllerBase } from '../../navigation/nav-controller-base'; import { NavOptions } from '../../navigation/nav-util'; @@ -303,10 +304,18 @@ export class Tab extends NavControllerBase { */ load(opts: NavOptions, done?: Function) { if (!this._loaded && this.root) { + this.setElementClass('show-tab', true); this.push(this.root, this.rootParams, opts, done); this._loaded = true; } else { + // if this is not the Tab's initial load then we need + // to refresh the tabbar and content dimensions to be sure + // they're lined up correctly + nativeRaf(() => { + var content = this.getActive().getIONContent(); + content.resize(); + }); done(true); } } diff --git a/src/components/tabs/tabs.ts b/src/components/tabs/tabs.ts index 47d69874b2e..ee680e941bf 100644 --- a/src/components/tabs/tabs.ts +++ b/src/components/tabs/tabs.ts @@ -2,7 +2,6 @@ import { AfterViewInit, Component, ElementRef, EventEmitter, Input, Output, Opti import { App } from '../app/app'; import { Config } from '../../config/config'; -import { Content } from '../content/content'; import { DeepLinker } from '../../navigation/deep-linker'; import { Ion } from '../ion'; import { isBlank } from '../../util/util'; @@ -422,16 +421,6 @@ export class Tabs extends Ion implements AfterViewInit { if (this._selectHistory[this._selectHistory.length - 1] !== selectedTab.id) { this._selectHistory.push(selectedTab.id); } - - // if this is not the Tab's initial load then we need - // to refresh the tabbar and content dimensions to be sure - // they're lined up correctly - if (alreadyLoaded && selectedPage) { - let content = selectedPage.getIONContent(); - if (content) { - content.resize(); - } - } }); } diff --git a/src/components/tabs/test/badges/app-module.ts b/src/components/tabs/test/badges/app-module.ts index 7ceae67e32d..ad2e87e5e36 100644 --- a/src/components/tabs/test/badges/app-module.ts +++ b/src/components/tabs/test/badges/app-module.ts @@ -12,6 +12,7 @@ export class E2EPage {} ` ion-tabs { margin-bottom: 20px; + contain: none; } `, ` diff --git a/src/components/tabs/test/colors/app-module.ts b/src/components/tabs/test/colors/app-module.ts index be0eafc1b50..f2790f3e51b 100644 --- a/src/components/tabs/test/colors/app-module.ts +++ b/src/components/tabs/test/colors/app-module.ts @@ -13,6 +13,7 @@ export class E2EPage {} ` ion-tabs { margin-bottom: 20px; + contain: none; } `, diff --git a/src/components/tabs/test/tab-bar-scenarios/app-module.ts b/src/components/tabs/test/tab-bar-scenarios/app-module.ts index 684f7a1dd98..0a6a90564de 100644 --- a/src/components/tabs/test/tab-bar-scenarios/app-module.ts +++ b/src/components/tabs/test/tab-bar-scenarios/app-module.ts @@ -13,6 +13,7 @@ export class E2EPage {} ` ion-tabs { margin-bottom: 20px; + contain: none; } `, ` diff --git a/src/components/tap-click/tap-click.ts b/src/components/tap-click/tap-click.ts index 8ef5baea892..a7bfd5011b4 100644 --- a/src/components/tap-click/tap-click.ts +++ b/src/components/tap-click/tap-click.ts @@ -4,7 +4,7 @@ import { ActivatorBase } from './activator-base'; import { Activator } from './activator'; import { App } from '../app/app'; import { Config } from '../../config/config'; -import { assert } from '../../util/util'; +import { assert, runInDev } from '../../util/util'; import { hasPointerMoved, pointerCoord } from '../../util/dom'; import { RippleActivator } from './ripple'; import { UIEventManager, PointerEvents, PointerEventType } from '../../util/ui-event-manager'; @@ -20,6 +20,7 @@ export class TapClick { private startCoord: any; private events: UIEventManager = new UIEventManager(false); private pointerEvents: PointerEvents; + private lastTouchEnd: number; constructor( config: Config, @@ -57,6 +58,8 @@ export class TapClick { this.startCoord = null; return false; } + + this.lastTouchEnd = 0; this.startCoord = pointerCoord(ev); this.activator && this.activator.downAction(ev, activatableEle, this.startCoord); return true; @@ -71,6 +74,8 @@ export class TapClick { } pointerEnd(ev: any, type: PointerEventType) { + runInDev(() => this.lastTouchEnd = Date.now()); + if (!this.startCoord) { return; } @@ -108,6 +113,7 @@ export class TapClick { console.debug(`click prevent ${preventReason} ${Date.now()}`); ev.preventDefault(); ev.stopPropagation(); + return; } else if (this.activator) { // cool, a click is gonna happen, let's tell the activator @@ -117,6 +123,19 @@ export class TapClick { this.activator.clickAction(ev, activatableEle, this.startCoord); } } + runInDev(() => { + if (this.lastTouchEnd) { + let diff = Date.now() - this.lastTouchEnd; + if (diff < 100) { + console.debug(`FAST click dispatched. Delay(ms):`, diff); + } else { + console.warn(`SLOW click dispatched. Delay(ms):`, diff, ev); + } + this.lastTouchEnd = null; + } else { + console.debug('Click dispatched. Unknown delay'); + } + }); } handleTapPolyfill(ev: any) { diff --git a/src/util/util.ts b/src/util/util.ts index 6a63c92c4d3..26fde65cc1c 100644 --- a/src/util/util.ts +++ b/src/util/util.ts @@ -181,6 +181,13 @@ const ASSERT_ENABLED = true; /** * @private */ + +function _runInDev(fn: Function) { + if (ASSERT_ENABLED === true) { + return fn(); + } +} + function _assert(actual: any, reason?: string) { if (!actual && ASSERT_ENABLED === true) { let message = 'IONIC ASSERT: ' + reason; @@ -191,3 +198,4 @@ function _assert(actual: any, reason?: string) { } export { _assert as assert}; +export { _runInDev as runInDev};