mirror of
https://github.com/ionic-team/ionic-framework.git
synced 2025-08-18 19:21:34 +08:00
fix(router): route information is stateless
This commit is contained in:
@ -3,9 +3,9 @@ import { Config, QueueController } from '../../interface';
|
|||||||
import { debounce } from '../../utils/helpers';
|
import { debounce } from '../../utils/helpers';
|
||||||
import { printRedirects, printRoutes } from './utils/debug';
|
import { printRedirects, printRoutes } from './utils/debug';
|
||||||
import { readNavState, waitUntilNavNode, writeNavState } from './utils/dom';
|
import { readNavState, waitUntilNavNode, writeNavState } from './utils/dom';
|
||||||
import { RouteChain, RouteRedirect, RouterDirection, RouterEventDetail } from './utils/interface';
|
import { RouteChain, RouterDirection, RouterEventDetail } from './utils/interface';
|
||||||
import { routeRedirect, routerIDsToChain, routerPathToChain } from './utils/matching';
|
import { routeRedirect, routerIDsToChain, routerPathToChain } from './utils/matching';
|
||||||
import { flattenRouterTree, readRedirects, readRoutes } from './utils/parser';
|
import { readRedirects, readRoutes } from './utils/parser';
|
||||||
import { chainToPath, generatePath, parsePath, readPath, writePath } from './utils/path';
|
import { chainToPath, generatePath, parsePath, readPath, writePath } from './utils/path';
|
||||||
|
|
||||||
|
|
||||||
@ -14,9 +14,7 @@ import { chainToPath, generatePath, parsePath, readPath, writePath } from './uti
|
|||||||
})
|
})
|
||||||
export class Router {
|
export class Router {
|
||||||
|
|
||||||
private routes: RouteChain[] = [];
|
|
||||||
private previousPath: string|null = null;
|
private previousPath: string|null = null;
|
||||||
private redirects: RouteRedirect[] = [];
|
|
||||||
private busy = false;
|
private busy = false;
|
||||||
private state = 0;
|
private state = 0;
|
||||||
private lastState = 0;
|
private lastState = 0;
|
||||||
@ -59,17 +57,11 @@ export class Router {
|
|||||||
await waitUntilNavNode(this.win);
|
await waitUntilNavNode(this.win);
|
||||||
console.debug('[ion-router] found nav');
|
console.debug('[ion-router] found nav');
|
||||||
|
|
||||||
const tree = readRoutes(this.el);
|
await this.onRoutesChanged();
|
||||||
this.routes = flattenRouterTree(tree);
|
|
||||||
this.redirects = readRedirects(this.el);
|
|
||||||
|
|
||||||
this.win.addEventListener('ionRouteRedirectChanged', debounce(this.onRedirectChanged.bind(this), 10));
|
this.win.addEventListener('ionRouteRedirectChanged', debounce(this.onRedirectChanged.bind(this), 10));
|
||||||
this.win.addEventListener('ionRouteDataChanged', debounce(this.onRoutesChanged.bind(this), 100));
|
this.win.addEventListener('ionRouteDataChanged', debounce(this.onRoutesChanged.bind(this), 100));
|
||||||
|
this.onRedirectChanged();
|
||||||
const changed = await this.writeNavStateRoot(this.getPath(), RouterDirection.None);
|
|
||||||
if (!changed) {
|
|
||||||
console.error('[ion-router] did not change on will load');
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Listen('window:popstate')
|
@Listen('window:popstate')
|
||||||
@ -81,17 +73,14 @@ export class Router {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private onRedirectChanged() {
|
private onRedirectChanged() {
|
||||||
this.redirects = readRedirects(this.el);
|
|
||||||
const path = this.getPath();
|
const path = this.getPath();
|
||||||
if (path && routeRedirect(path, this.redirects)) {
|
if (path && routeRedirect(path, readRedirects(this.el))) {
|
||||||
this.writeNavStateRoot(path, RouterDirection.None);
|
this.writeNavStateRoot(path, RouterDirection.None);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private onRoutesChanged() {
|
private onRoutesChanged() {
|
||||||
const tree = readRoutes(this.el);
|
return this.writeNavStateRoot(this.getPath(), RouterDirection.None);
|
||||||
this.routes = flattenRouterTree(tree);
|
|
||||||
this.writeNavStateRoot(this.getPath(), RouterDirection.None);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private historyDirection() {
|
private historyDirection() {
|
||||||
@ -117,8 +106,8 @@ export class Router {
|
|||||||
printDebug() {
|
printDebug() {
|
||||||
console.debug('CURRENT PATH', this.getPath());
|
console.debug('CURRENT PATH', this.getPath());
|
||||||
console.debug('PREVIOUS PATH', this.previousPath);
|
console.debug('PREVIOUS PATH', this.previousPath);
|
||||||
printRoutes(this.routes);
|
printRoutes(readRoutes(this.el));
|
||||||
printRedirects(this.redirects);
|
printRedirects(readRedirects(this.el));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Method()
|
@Method()
|
||||||
@ -127,7 +116,8 @@ export class Router {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
const { ids, outlet } = readNavState(this.win.document.body);
|
const { ids, outlet } = readNavState(this.win.document.body);
|
||||||
const chain = routerIDsToChain(ids, this.routes);
|
const routes = readRoutes(this.el);
|
||||||
|
const chain = routerIDsToChain(ids, routes);
|
||||||
if (!chain) {
|
if (!chain) {
|
||||||
console.warn('[ion-router] no matching URL for ', ids.map(i => i.id));
|
console.warn('[ion-router] no matching URL for ', ids.map(i => i.id));
|
||||||
return false;
|
return false;
|
||||||
@ -149,9 +139,9 @@ export class Router {
|
|||||||
@Method()
|
@Method()
|
||||||
push(url: string, direction = RouterDirection.Forward) {
|
push(url: string, direction = RouterDirection.Forward) {
|
||||||
const path = parsePath(url);
|
const path = parsePath(url);
|
||||||
this.setPath(path, direction);
|
|
||||||
|
|
||||||
console.debug('[ion-router] URL pushed -> updating nav', url, direction);
|
console.debug('[ion-router] URL pushed -> updating nav', url, direction);
|
||||||
|
|
||||||
|
this.setPath(path, direction);
|
||||||
return this.writeNavStateRoot(path, direction);
|
return this.writeNavStateRoot(path, direction);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -165,16 +155,18 @@ export class Router {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// lookup redirect rule
|
// lookup redirect rule
|
||||||
const redirect = routeRedirect(path, this.redirects);
|
const redirects = readRedirects(this.el);
|
||||||
|
const redirect = routeRedirect(path, redirects);
|
||||||
let redirectFrom: string[]|null = null;
|
let redirectFrom: string[]|null = null;
|
||||||
if (redirect) {
|
if (redirect) {
|
||||||
this.setPath(redirect.to!, direction);
|
this.setPath(redirect.to, direction);
|
||||||
redirectFrom = redirect.from;
|
redirectFrom = redirect.from;
|
||||||
path = redirect.to!;
|
path = redirect.to;
|
||||||
}
|
}
|
||||||
|
|
||||||
// lookup route chain
|
// lookup route chain
|
||||||
const chain = routerPathToChain(path, this.routes);
|
const routes = readRoutes(this.el);
|
||||||
|
const chain = routerPathToChain(path, routes);
|
||||||
if (!chain) {
|
if (!chain) {
|
||||||
console.error('[ion-router] the path does not match any route');
|
console.error('[ion-router] the path does not match any route');
|
||||||
return false;
|
return false;
|
||||||
|
@ -19,7 +19,7 @@ export const enum RouterDirection {
|
|||||||
|
|
||||||
export interface RouteRedirect {
|
export interface RouteRedirect {
|
||||||
from: string[];
|
from: string[];
|
||||||
to: string[]|undefined;
|
to?: string[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface RouteWrite {
|
export interface RouteWrite {
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { RouteChain, RouteID, RouteRedirect } from './interface';
|
import { RouteChain, RouteID, RouteRedirect } from './interface';
|
||||||
|
|
||||||
|
|
||||||
export function matchesRedirect(input: string[], route: RouteRedirect): boolean {
|
export function matchesRedirect(input: string[], route: RouteRedirect): route is Required<RouteRedirect> {
|
||||||
const {from, to} = route;
|
const {from, to} = route;
|
||||||
if (to === undefined) {
|
if (to === undefined) {
|
||||||
return false;
|
return false;
|
||||||
@ -23,13 +23,8 @@ export function matchesRedirect(input: string[], route: RouteRedirect): boolean
|
|||||||
return from.length === input.length;
|
return from.length === input.length;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function routeRedirect(path: string[], routes: RouteRedirect[]): RouteRedirect|null {
|
export function routeRedirect(path: string[], routes: RouteRedirect[]) {
|
||||||
for (const route of routes) {
|
return routes.find(route => matchesRedirect(path, route)) as Required<RouteRedirect> | undefined;
|
||||||
if (matchesRedirect(path, route)) {
|
|
||||||
return route;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -14,7 +14,11 @@ export function readRedirects(root: Element): RouteRedirect[] {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export function readRoutes(root: Element, node = root): RouteTree {
|
export function readRoutes(root: Element): RouteChain[] {
|
||||||
|
return flattenRouterTree(readRouteNodes(root));
|
||||||
|
}
|
||||||
|
|
||||||
|
export function readRouteNodes(root: Element, node = root): RouteTree {
|
||||||
return (Array.from(node.children) as HTMLIonRouteElement[])
|
return (Array.from(node.children) as HTMLIonRouteElement[])
|
||||||
.filter(el => el.tagName === 'ION-ROUTE' && el.component)
|
.filter(el => el.tagName === 'ION-ROUTE' && el.component)
|
||||||
.map(el => {
|
.map(el => {
|
||||||
@ -26,7 +30,7 @@ export function readRoutes(root: Element, node = root): RouteTree {
|
|||||||
path: parsePath(readProp(el, 'url')),
|
path: parsePath(readProp(el, 'url')),
|
||||||
id: component.toLowerCase(),
|
id: component.toLowerCase(),
|
||||||
params: el.componentProps,
|
params: el.componentProps,
|
||||||
children: readRoutes(root, el)
|
children: readRouteNodes(root, el)
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user