mirror of
https://github.com/ionic-team/ionic-framework.git
synced 2025-08-20 20:33:32 +08:00
transition updates
This commit is contained in:
@ -1,8 +1,19 @@
|
||||
import {NgElement} from 'angular2/angular2';
|
||||
import * as util from 'ionic/util';
|
||||
import {Transition} from 'ionic/ionic';
|
||||
|
||||
|
||||
const STAGED_STATE = 'staged';
|
||||
const STAGED_ENTERING_STATE = 'staged-enter';
|
||||
const STAGED_LEAVING_STATE = 'staged-leave';
|
||||
const ACTIVELY_ENTERING_STATE = 'entering';
|
||||
const ACTIVELY_LEAVING_STATE = 'leaving';
|
||||
const ACTIVE_STATE = 'active';
|
||||
const CACHED_STATE = 'cached';
|
||||
|
||||
|
||||
/*
|
||||
* Used be tabs and nav
|
||||
* Used by tabs and nav
|
||||
*/
|
||||
export class NavBase {
|
||||
constructor(
|
||||
@ -23,47 +34,174 @@ export class NavBase {
|
||||
containsClass(Class) {
|
||||
for (let i = 0; i < this._stack.length; i++) {
|
||||
if (this._stack[i].Class === Class) {
|
||||
return true
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false
|
||||
return false;
|
||||
}
|
||||
|
||||
set initial(Class) {
|
||||
if (!this.initialized) {
|
||||
this.initialized = true
|
||||
this.push(Class, {}, {
|
||||
animation: 'none'
|
||||
});
|
||||
this.push(Class);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Push a new view into the history stack.
|
||||
*/
|
||||
push(Class: Function, params = {}, opts = {}) {
|
||||
let pushedItem = new NavStackData(Class, params);
|
||||
|
||||
this._stack.push(pushedItem);
|
||||
this.navItems.push(pushedItem);
|
||||
|
||||
return pushedItem.setup().then(() => {
|
||||
let current = this._getPrevious(pushedItem);
|
||||
current && current.leaveReverse(opts);
|
||||
return pushedItem.enter(opts);
|
||||
});
|
||||
getActiveItem() {
|
||||
for (let i = 0, ii = this.navItems.length; i < ii; i++) {
|
||||
if (this.navItems[i].state === ACTIVE_STATE) {
|
||||
return this.navItems[i];
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Pop a view off the history
|
||||
*/
|
||||
pop(opts = {}) {
|
||||
let current = this._stack.pop()
|
||||
let dest = this.last()
|
||||
getStagedEnteringItem() {
|
||||
for (let i = 0, ii = this.navItems.length; i < ii; i++) {
|
||||
if (this.navItems[i].state === STAGED_ENTERING_STATE) {
|
||||
return this.navItems[i];
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
dest && dest.enterReverse(opts)
|
||||
return current && current.leave(opts)
|
||||
.then(() => this._destroy(current))
|
||||
getStagedLeavingItem() {
|
||||
for (let i = 0, ii = this.navItems.length; i < ii; i++) {
|
||||
if (this.navItems[i].state === STAGED_LEAVING_STATE) {
|
||||
return this.navItems[i];
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
getLeavingItems() {
|
||||
let items = [];
|
||||
for (let i = 0, ii = this.navItems.length; i < ii; i++) {
|
||||
if (this.navItems[i].state === ACTIVELY_LEAVING_STATE || this.navItems[i].state === STAGED_LEAVING_STATE) {
|
||||
items.push(this.navItems[i]);
|
||||
}
|
||||
}
|
||||
return items;
|
||||
}
|
||||
|
||||
push(Class: Function, params = {}, opts = {}) {
|
||||
let resolve;
|
||||
let promise = new Promise(res => { resolve = res; });
|
||||
|
||||
// default the direction to "forward"
|
||||
opts.direction = opts.direction || 'forward';
|
||||
|
||||
// do not animate if this is the first in the stack
|
||||
if (!this._stack.length) {
|
||||
opts.animation = 'none';
|
||||
}
|
||||
|
||||
// the active item is going to be the leaving one (if one exists)
|
||||
let leavingItem = this.getActiveItem() || {};
|
||||
|
||||
// create a new NavStackItem
|
||||
let enteringItem = new NavStackItem(Class, params);
|
||||
|
||||
// set that this item is staged (it's not ready to be animated in yet)
|
||||
enteringItem.state = STAGED_STATE;
|
||||
|
||||
// add the item to the stack (just renders in the DOM, doesn't animate yet)
|
||||
this._stack.push(enteringItem);
|
||||
this.navItems.push(enteringItem);
|
||||
|
||||
// start the transition
|
||||
this.transition(enteringItem, leavingItem, opts).then(() => {
|
||||
console.log('push completed');
|
||||
resolve();
|
||||
});
|
||||
|
||||
return promise;
|
||||
}
|
||||
|
||||
pop(opts = {}) {
|
||||
let resolve;
|
||||
let promise = new Promise(res => { resolve = res; });
|
||||
|
||||
// default the direction to "back"
|
||||
opts.direction = opts.direction || 'back';
|
||||
|
||||
// remove the last item
|
||||
this._stack.pop();
|
||||
|
||||
// the entering item is now the new last item
|
||||
let enteringItem = this.last()
|
||||
|
||||
// get the active item and set that it is staged to be leaving
|
||||
// was probably the one popped from the stack
|
||||
let leavingItem = this.getActiveItem() || {};
|
||||
|
||||
// start the transition
|
||||
this.transition(enteringItem, leavingItem, opts).then(() => {
|
||||
// transition completed, destroy the leaving item
|
||||
console.log('pop completed');
|
||||
this._destroy(leavingItem);
|
||||
resolve();
|
||||
});
|
||||
|
||||
return promise;
|
||||
}
|
||||
|
||||
transition(enteringItem, leavingItem, opts) {
|
||||
let resolve;
|
||||
let promise = new Promise(res => { resolve = res; });
|
||||
|
||||
// wait for the new item to complete setup
|
||||
enteringItem.setup().then(() => {
|
||||
|
||||
// get any items that are already staged to leave, or are actively leaving
|
||||
// since a different item will be leaving, reset any actively leaving items to cached
|
||||
let leavingItems = this.getLeavingItems();
|
||||
for (let i = 0; i < leavingItems.length; i++) {
|
||||
leavingItems[i].state = CACHED_STATE;
|
||||
}
|
||||
|
||||
// set that the leaving item is stage to be leaving
|
||||
leavingItem.state = STAGED_LEAVING_STATE;
|
||||
|
||||
// set that the new item pushed on the stack is staged to be entering
|
||||
// setting staged state is important for the transition logic to find the correct item
|
||||
enteringItem.state = STAGED_ENTERING_STATE;
|
||||
|
||||
// init the transition animation
|
||||
let transAnimation = Transition.create(this, opts);
|
||||
|
||||
// wait for the items to be fully staged
|
||||
transAnimation.stage().then(() => {
|
||||
|
||||
// update the state that the items are actively entering/leaving
|
||||
enteringItem.state = ACTIVELY_ENTERING_STATE;
|
||||
leavingItem.state = ACTIVELY_LEAVING_STATE;
|
||||
|
||||
// start the transition
|
||||
transAnimation.start().then(() => {
|
||||
|
||||
// transition has completed, update each item's state
|
||||
enteringItem.state = ACTIVE_STATE;
|
||||
leavingItem.state = CACHED_STATE;
|
||||
|
||||
// resolve that this push has completed
|
||||
resolve();
|
||||
|
||||
// on the next frame, hide the item that's cached
|
||||
util.dom.raf(() => {
|
||||
// ensure it's state is still cached
|
||||
if (leavingItem.state === CACHED_STATE && leavingItem.navItem) {
|
||||
// CSS default is display:none, so setting to '' does the trick
|
||||
leavingItem.navItem.domElement.style.display = '';
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
return promise;
|
||||
}
|
||||
|
||||
last() {
|
||||
@ -103,23 +241,18 @@ export class NavBase {
|
||||
return this.pop(opts)
|
||||
}
|
||||
|
||||
setStack(stack) {
|
||||
this._stack = stack.slice()
|
||||
this.navItems = stack.slice()
|
||||
}
|
||||
|
||||
remove(index) {
|
||||
const item = this._stack[index]
|
||||
this._stack.splice(index, 1)
|
||||
this._destroy(item)
|
||||
const item = this._stack[index];
|
||||
this._stack.splice(index, 1);
|
||||
this._destroy(item);
|
||||
}
|
||||
|
||||
_destroy(navItem) {
|
||||
util.array.remove(this.navItems, navItem)
|
||||
util.array.remove(this.navItems, navItem);
|
||||
}
|
||||
|
||||
_getPrevious(item) {
|
||||
return this._stack[ this._stack.indexOf(item) - 1 ]
|
||||
getPrevious(item) {
|
||||
return this._stack[ this._stack.indexOf(item) - 1 ];
|
||||
}
|
||||
|
||||
getToolbars(pos: String) {
|
||||
@ -128,7 +261,8 @@ export class NavBase {
|
||||
}
|
||||
}
|
||||
|
||||
class NavStackData {
|
||||
|
||||
class NavStackItem {
|
||||
constructor(ComponentClass, params = {}) {
|
||||
this.Class = ComponentClass;
|
||||
this.params = params;
|
||||
|
@ -1,5 +1,5 @@
|
||||
|
||||
<h1>First Page</h1>
|
||||
<h1 style="background:blue">First Page</h1>
|
||||
|
||||
<p>
|
||||
<button (click)="push()">Push (Go to 2nd)</button>
|
||||
|
@ -1,5 +1,5 @@
|
||||
|
||||
<h1>Second Page</h1>
|
||||
<h1 style="background:green">Second Page</h1>
|
||||
|
||||
<p>
|
||||
<button (click)="pop()">Pop (Go back to 1st)</button>
|
||||
|
@ -1,5 +1,5 @@
|
||||
|
||||
<h1>Third Page</h1>
|
||||
<h1 style="background:yellow">Third Page</h1>
|
||||
|
||||
<p>
|
||||
<button (click)="pop()">Pop (Go back to 2nd)</button>
|
||||
|
Reference in New Issue
Block a user