mirror of
https://github.com/ionic-team/ionic-framework.git
synced 2026-03-13 10:22:08 +08:00
feat(router): links trigger animations
This commit is contained in:
@@ -15,6 +15,7 @@ export class PageOne {
|
||||
</ion-header>
|
||||
<ion-content>
|
||||
page one
|
||||
<a href='#/two/second-page'>Ir a la page 2</a>
|
||||
</ion-content>
|
||||
</ion-page>
|
||||
];
|
||||
|
||||
@@ -193,13 +193,25 @@ export class Nav implements PublicNav, NavOutlet {
|
||||
}
|
||||
|
||||
@Method()
|
||||
setRouteId(id: string, _: any = {}): Promise<any> {
|
||||
assert(this.useRouter, 'routing is disabled');
|
||||
setRouteId(id: string, _: any = {}, direction: number): Promise<boolean> {
|
||||
const active = this.getActive();
|
||||
if (active && active.component === id) {
|
||||
return Promise.resolve(null);
|
||||
return Promise.resolve(false);
|
||||
}
|
||||
return this.setRoot(id);
|
||||
if (direction === 1) {
|
||||
return this.push(id).then(() => true);
|
||||
} else if (direction === -1 && this._canGoBack(id)) {
|
||||
return this.pop().then(() => true);
|
||||
}
|
||||
return this.setRoot(id).then(() => true);
|
||||
}
|
||||
|
||||
private _canGoBack(id: any) {
|
||||
if (!this.canGoBack()) {
|
||||
return false;
|
||||
}
|
||||
const view = this.views[this.views.length - 1];
|
||||
return view.component === id;
|
||||
}
|
||||
|
||||
@Method()
|
||||
@@ -215,7 +227,7 @@ export class Nav implements PublicNav, NavOutlet {
|
||||
getContentElement(): HTMLElement {
|
||||
const active = getActiveImpl(this);
|
||||
if (active) {
|
||||
active.element;
|
||||
return active.element;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
export interface NavOutlet {
|
||||
setRouteId(id: any, data?: any): Promise<any>;
|
||||
setRouteId(id: any, data: any, direction: number): Promise<boolean>;
|
||||
getRouteId(): string;
|
||||
getContentElement(): HTMLElement | null;
|
||||
}
|
||||
@@ -28,22 +28,24 @@ export class RouterSegments {
|
||||
}
|
||||
}
|
||||
|
||||
export function writeNavState(root: HTMLElement, chain: RouterEntries, index = 0): Promise<void> {
|
||||
export function writeNavState(root: HTMLElement, chain: RouterEntries, index: number, direction: number): Promise<void> {
|
||||
if (index >= chain.length) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
const route = chain[index];
|
||||
const node = breadthFirstSearch(root);
|
||||
if (!node) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
return node.componentOnReady()
|
||||
.then(() => node.setRouteId(route.id, route.props))
|
||||
.then(() => {
|
||||
.then(() => node.setRouteId(route.id, route.props, direction))
|
||||
.then(changed => {
|
||||
if (changed) {
|
||||
direction = 0;
|
||||
}
|
||||
const nextEl = node.getContentElement();
|
||||
if (nextEl) {
|
||||
return writeNavState(nextEl, chain, index + 1);
|
||||
return writeNavState(nextEl, chain, index + 1, direction);
|
||||
}
|
||||
return null;
|
||||
});
|
||||
@@ -199,18 +201,20 @@ export function breadthFirstSearch(root: HTMLElement): NavOutletElement | null {
|
||||
return null;
|
||||
}
|
||||
|
||||
export function writePath(history: History, base: string, usePath: boolean, path: string[], isPop: boolean) {
|
||||
export function writePath(history: History, base: string, usePath: boolean, path: string[], isPop: boolean, state: number) {
|
||||
path = [base, ...path];
|
||||
let url = generatePath(path);
|
||||
if (usePath) {
|
||||
url = '#' + url;
|
||||
}
|
||||
state++;
|
||||
if (isPop) {
|
||||
history.back();
|
||||
history.replaceState(null, null, url);
|
||||
history.replaceState(state, null, url);
|
||||
} else {
|
||||
history.pushState(null, null, url);
|
||||
history.pushState(state, null, url);
|
||||
}
|
||||
return state;
|
||||
}
|
||||
|
||||
export function readPath(loc: Location, base: string, useHash: boolean): string[] | null {
|
||||
|
||||
@@ -10,6 +10,7 @@ export class Router {
|
||||
|
||||
private routes: RouterEntries;
|
||||
private busy = false;
|
||||
private state = 0;
|
||||
|
||||
@Prop({ context: 'config' }) config: Config;
|
||||
@Prop({ context: 'dom' }) dom: DomController;
|
||||
@@ -30,8 +31,12 @@ export class Router {
|
||||
});
|
||||
}
|
||||
|
||||
@Listen('window:hashchange')
|
||||
@Listen('window:popstate')
|
||||
protected onURLHashChanged() {
|
||||
if (window.history.state === null) {
|
||||
this.state++;
|
||||
window.history.replaceState(this.state, document.title, document.location.href);
|
||||
}
|
||||
if (!this.busy) {
|
||||
console.debug('[OUT] hash changed -> write nav state');
|
||||
this.writeNavStateRoot();
|
||||
@@ -43,35 +48,34 @@ export class Router {
|
||||
if (this.busy) {
|
||||
return;
|
||||
}
|
||||
|
||||
console.debug('[IN] nav changed -> update URL');
|
||||
const { stack, pivot } = this.readNavState();
|
||||
const { path, routes} = matchPath(stack, this.routes);
|
||||
const { path, routes } = matchPath(stack, this.routes);
|
||||
if (pivot) {
|
||||
// readNavState() found a pivot that is not initialized
|
||||
console.debug('[IN] pivot uninitialized -> write partial nav state');
|
||||
this.writeNavState(pivot, [], routes);
|
||||
this.writeNavState(pivot, [], routes, 0);
|
||||
}
|
||||
|
||||
const isPop = ev.detail.isPop === true;
|
||||
this.writePath(path, isPop);
|
||||
}
|
||||
|
||||
|
||||
private writeNavStateRoot(): Promise<any> {
|
||||
const node = document.querySelector('ion-app') as HTMLElement;
|
||||
const currentPath = this.readPath();
|
||||
const direction = window.history.state >= this.state ? 1 : -1;
|
||||
if (currentPath) {
|
||||
return this.writeNavState(node, currentPath, this.routes);
|
||||
return this.writeNavState(node, currentPath, this.routes, direction);
|
||||
}
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
private writeNavState(node: any, path: string[], routes: RouterEntries): Promise<any> {
|
||||
private writeNavState(node: any, path: string[], routes: RouterEntries, direction: number): Promise<any> {
|
||||
const chain = matchRouteChain(path, routes);
|
||||
|
||||
this.busy = true;
|
||||
return writeNavState(node, chain)
|
||||
return writeNavState(node, chain, 0, direction)
|
||||
.catch(err => console.error(err))
|
||||
.then(() => this.busy = false);
|
||||
}
|
||||
@@ -82,7 +86,7 @@ export class Router {
|
||||
}
|
||||
|
||||
private writePath(path: string[], isPop: boolean) {
|
||||
writePath(window.history, this.base, this.useHash, path, isPop);
|
||||
this.state = writePath(window.history, this.base, this.useHash, path, isPop, this.state);
|
||||
}
|
||||
|
||||
private readPath(): string[] | null {
|
||||
|
||||
@@ -14,12 +14,17 @@
|
||||
|
||||
<ion-router>
|
||||
<ion-route path="/" sel="tab1"> </ion-route>
|
||||
|
||||
<ion-route path="/two" sel="tab2">
|
||||
<ion-route path="/" sel="page-one"> </ion-route>
|
||||
<ion-route path="/second-page" sel="page-two"> </ion-route>
|
||||
<ion-route path="/thee-page" sel="page-three"> </ion-route>
|
||||
</ion-route>
|
||||
|
||||
<ion-route path="/three" sel="tab-three"> </ion-route>
|
||||
<ion-route path="/four" sel="tab4"> </ion-route>
|
||||
<ion-route path="/four" sel="tab4">
|
||||
<ion-route path="/" sel="page-two"> </ion-route>
|
||||
</ion-route>
|
||||
</ion-router>
|
||||
|
||||
<ion-tabs>
|
||||
@@ -43,7 +48,7 @@
|
||||
title="Messages"
|
||||
icon="chatboxes"
|
||||
name="tab-four">
|
||||
INLINE CONTENT
|
||||
<ion-nav></ion-nav>
|
||||
</ion-tab>
|
||||
</ion-tabs>
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ import { FrameworkDelegate } from '../..';
|
||||
})
|
||||
export class Tab {
|
||||
|
||||
// private loaded = false;
|
||||
private loaded = false;
|
||||
@Element() el: HTMLElement;
|
||||
|
||||
@State() init = false;
|
||||
@@ -81,36 +81,12 @@ export class Tab {
|
||||
@Method()
|
||||
setActive(active: boolean): Promise<any> {
|
||||
this.active = active;
|
||||
if (active) {
|
||||
const nav = getNavAsChildIfExists(this.el);
|
||||
if (nav) {
|
||||
// the tab's nav has been initialized externally
|
||||
|
||||
return ensureExternalRounterController().then((externalRouterController) => {
|
||||
if (externalRouterController.getExternalNavPromise()) {
|
||||
return (externalRouterController.getExternalNavPromise() as Promise<any>).then(() => {
|
||||
externalRouterController.clearExternalNavPromise();
|
||||
});
|
||||
}
|
||||
|
||||
// the tab's nav has not been initialized externally, so
|
||||
// check if we need to initiailize it
|
||||
return (nav as any).componentOnReady().then(() => {
|
||||
return nav.onAllTransitionsComplete();
|
||||
}).then(() => {
|
||||
if (!nav.getViews().length && !nav.isTransitioning() && !nav.initialized) {
|
||||
return nav.setRoot(nav.root);
|
||||
}
|
||||
return Promise.resolve();
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/*if (this.loaded || !active) {
|
||||
if (!active) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
if (this.loaded) {
|
||||
return this.configChildgNav();
|
||||
}
|
||||
this.loaded = true;
|
||||
|
||||
let promise: Promise<any>;
|
||||
@@ -122,9 +98,7 @@ export class Tab {
|
||||
} else {
|
||||
promise = Promise.resolve();
|
||||
}
|
||||
return promise.then(() => this.fireChildren());
|
||||
*/
|
||||
return Promise.resolve();
|
||||
return promise.then(() => this.configChildgNav());
|
||||
}
|
||||
|
||||
@Method()
|
||||
@@ -138,16 +112,32 @@ export class Tab {
|
||||
return null;
|
||||
}
|
||||
|
||||
/*private fireChildren() {
|
||||
private configChildgNav(): Promise<any|void> {
|
||||
const nav = getNavAsChildIfExists(this.el);
|
||||
if (nav && nav.getViews().length === 0 && nav.root) {
|
||||
// we need to initialize
|
||||
return nav.setRoot(nav.root);
|
||||
if (nav) {
|
||||
// the tab's nav has been initialized externally
|
||||
return ensureExternalRounterController().then<void|any>((externalRouterController) => {
|
||||
const externalNavPromise = externalRouterController.getExternalNavPromise();
|
||||
if (externalNavPromise) {
|
||||
return externalNavPromise.then(() => {
|
||||
externalRouterController.clearExternalNavPromise();
|
||||
});
|
||||
}
|
||||
|
||||
// the tab's nav has not been initialized externally, so
|
||||
// check if we need to initiailize it
|
||||
return nav.componentOnReady()
|
||||
.then(() => nav.onAllTransitionsComplete())
|
||||
.then<any>(() => {
|
||||
if (nav.getViews().length === 0 && !nav.isTransitioning() && !nav.initialized) {
|
||||
return nav.setRoot(nav.root);
|
||||
}
|
||||
return Promise.resolve();
|
||||
});
|
||||
});
|
||||
}
|
||||
// it's already been initialized if it exists
|
||||
return Promise.resolve();
|
||||
}
|
||||
*/
|
||||
|
||||
hostData() {
|
||||
const visible = this.active && this.selected;
|
||||
@@ -166,7 +156,7 @@ export class Tab {
|
||||
}
|
||||
}
|
||||
|
||||
/*function attachViewToDom(container: HTMLElement, cmp: string): Promise<any> {
|
||||
function attachViewToDom(container: HTMLElement, cmp: string): Promise<any> {
|
||||
const el = document.createElement(cmp) as HTMLStencilElement;
|
||||
container.appendChild(el);
|
||||
if (el.componentOnReady) {
|
||||
@@ -174,4 +164,3 @@ export class Tab {
|
||||
}
|
||||
return Promise.resolve();
|
||||
}
|
||||
*/
|
||||
|
||||
@@ -160,12 +160,12 @@ export class Tabs implements NavOutlet {
|
||||
}
|
||||
|
||||
@Method()
|
||||
setRouteId(id: any, _: any = {}): Promise<void> {
|
||||
if (this.selectedTab === id) {
|
||||
return Promise.resolve();
|
||||
setRouteId(id: any): Promise<boolean> {
|
||||
if (this.selectedTab && this.selectedTab.getRouteId() === id) {
|
||||
return Promise.resolve(false);
|
||||
}
|
||||
const tab = this.tabs.find(t => id === t.getRouteId());
|
||||
return this.select(tab);
|
||||
return this.select(tab).then(() => true);
|
||||
}
|
||||
|
||||
|
||||
@@ -185,13 +185,13 @@ export class Tabs implements NavOutlet {
|
||||
|
||||
private initTabs() {
|
||||
const tabs = this.tabs = Array.from(this.el.querySelectorAll('ion-tab'));
|
||||
const tabPromises: Promise<any>[] = [];
|
||||
for (const tab of tabs) {
|
||||
const tabPromises = tabs.map(tab => {
|
||||
const id = `t-${this.tabsId}-${++this.ids}`;
|
||||
tab.btnId = 'tab-' + id;
|
||||
tab.id = 'tabpanel-' + id;
|
||||
tabPromises.push((tab as any).componentOnReady());
|
||||
}
|
||||
return tab.componentOnReady();
|
||||
});
|
||||
|
||||
return Promise.all(tabPromises);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user