perf(tabs): improve tab switching response

This commit is contained in:
Manu Mtz.-Almeida
2016-11-28 16:00:41 +01:00
committed by Adam Bradley
parent d2ebac3d27
commit 907191bbc2
10 changed files with 67 additions and 16 deletions

View File

@@ -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);

View File

@@ -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;

View File

@@ -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) {

View File

@@ -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);
}
}

View File

@@ -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 = <Content>selectedPage.getIONContent();
if (content) {
content.resize();
}
}
});
}

View File

@@ -12,6 +12,7 @@ export class E2EPage {}
`
ion-tabs {
margin-bottom: 20px;
contain: none;
}
`,
`

View File

@@ -13,6 +13,7 @@ export class E2EPage {}
`
ion-tabs {
margin-bottom: 20px;
contain: none;
}
`,

View File

@@ -13,6 +13,7 @@ export class E2EPage {}
`
ion-tabs {
margin-bottom: 20px;
contain: none;
}
`,
`

View File

@@ -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) {

View File

@@ -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};