mirror of
https://github.com/ionic-team/ionic-framework.git
synced 2026-03-13 10:22:08 +08:00
perf(tabs): improve tab switching response
This commit is contained in:
committed by
Adam Bradley
parent
d2ebac3d27
commit
907191bbc2
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@ export class E2EPage {}
|
||||
`
|
||||
ion-tabs {
|
||||
margin-bottom: 20px;
|
||||
contain: none;
|
||||
}
|
||||
`,
|
||||
`
|
||||
|
||||
@@ -13,6 +13,7 @@ export class E2EPage {}
|
||||
`
|
||||
ion-tabs {
|
||||
margin-bottom: 20px;
|
||||
contain: none;
|
||||
}
|
||||
`,
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@ export class E2EPage {}
|
||||
`
|
||||
ion-tabs {
|
||||
margin-bottom: 20px;
|
||||
contain: none;
|
||||
}
|
||||
`,
|
||||
`
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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};
|
||||
|
||||
Reference in New Issue
Block a user