mirror of
https://github.com/ionic-team/ionic-framework.git
synced 2026-03-13 10:22:08 +08:00
fix(router): dynamic redirects
This commit is contained in:
1
core/src/components.d.ts
vendored
1
core/src/components.d.ts
vendored
@@ -5114,6 +5114,7 @@ declare global {
|
||||
namespace StencilComponents {
|
||||
interface IonRouter {
|
||||
'navChanged': (direction: RouterDirection) => Promise<boolean>;
|
||||
'printDebug': () => void;
|
||||
'push': (url: string, direction?: RouterDirection) => Promise<boolean>;
|
||||
/**
|
||||
* By default `ion-router` will match the routes at the root path ("/"). That can be changed when T
|
||||
|
||||
@@ -150,6 +150,9 @@ By default, this property is `true`, change to `false` to allow hash-less URLs.
|
||||
#### navChanged()
|
||||
|
||||
|
||||
#### printDebug()
|
||||
|
||||
|
||||
#### push()
|
||||
|
||||
|
||||
|
||||
@@ -1,11 +1,14 @@
|
||||
import { Component, Element, Event, EventEmitter, Listen, Method, Prop } from '@stencil/core';
|
||||
import { Config, QueueController } from '../../interface';
|
||||
import { debounce } from '../../utils/helpers';
|
||||
import { printRedirects, printRoutes } from './utils/debug';
|
||||
import { readNavState, waitUntilNavNode, writeNavState } from './utils/dom';
|
||||
import { RouteChain, RouteRedirect, RouterDirection, RouterEventDetail } from './utils/interface';
|
||||
import { routeRedirect, routerIDsToChain, routerPathToChain } from './utils/matching';
|
||||
import { flattenRouterTree, readRedirects, readRoutes } from './utils/parser';
|
||||
import { chainToPath, generatePath, parsePath, readPath, writePath } from './utils/path';
|
||||
|
||||
|
||||
@Component({
|
||||
tag: 'ion-router'
|
||||
})
|
||||
@@ -15,10 +18,8 @@ export class Router {
|
||||
private previousPath: string|null = null;
|
||||
private redirects: RouteRedirect[] = [];
|
||||
private busy = false;
|
||||
private init = false;
|
||||
private state = 0;
|
||||
private lastState = 0;
|
||||
private timer: any;
|
||||
|
||||
@Element() el!: HTMLElement;
|
||||
|
||||
@@ -62,47 +63,15 @@ export class Router {
|
||||
this.routes = flattenRouterTree(tree);
|
||||
this.redirects = readRedirects(this.el);
|
||||
|
||||
this.win.addEventListener('ionRouteRedirectChanged', debounce(this.onRedirectChanged.bind(this), 10));
|
||||
this.win.addEventListener('ionRouteDataChanged', debounce(this.onRoutesChanged.bind(this), 100));
|
||||
|
||||
const changed = await this.writeNavStateRoot(this.getPath(), RouterDirection.None);
|
||||
if (!changed) {
|
||||
console.error('[ion-router] did not change on will load');
|
||||
}
|
||||
}
|
||||
|
||||
componentDidLoad() {
|
||||
this.init = true;
|
||||
console.debug('[ion-router] router did load');
|
||||
}
|
||||
|
||||
@Listen('ionRouteRedirectChanged')
|
||||
protected onRedirectChanged(ev: CustomEvent) {
|
||||
if (!this.init) {
|
||||
return;
|
||||
}
|
||||
console.debug('[ion-router] redirect data changed', ev.target);
|
||||
this.redirects = readRedirects(this.el);
|
||||
}
|
||||
|
||||
@Listen('ionRouteDataChanged')
|
||||
protected onRoutesChanged(ev: CustomEvent) {
|
||||
if (!this.init) {
|
||||
return;
|
||||
}
|
||||
console.debug('[ion-router] route data changed', ev.target, ev.detail);
|
||||
|
||||
// schedule write
|
||||
if (this.timer) {
|
||||
clearTimeout(this.timer);
|
||||
this.timer = undefined;
|
||||
}
|
||||
this.timer = setTimeout(() => {
|
||||
console.debug('[ion-router] data changed -> update nav');
|
||||
const tree = readRoutes(this.el);
|
||||
this.routes = flattenRouterTree(tree);
|
||||
this.writeNavStateRoot(this.getPath(), RouterDirection.None);
|
||||
this.timer = undefined;
|
||||
}, 100);
|
||||
}
|
||||
|
||||
@Listen('window:popstate')
|
||||
protected onPopState() {
|
||||
const direction = this.historyDirection();
|
||||
@@ -111,6 +80,20 @@ export class Router {
|
||||
return this.writeNavStateRoot(path, direction);
|
||||
}
|
||||
|
||||
private onRedirectChanged() {
|
||||
this.redirects = readRedirects(this.el);
|
||||
const path = this.getPath();
|
||||
if (path && routeRedirect(path, this.redirects)) {
|
||||
this.writeNavStateRoot(path, RouterDirection.None);
|
||||
}
|
||||
}
|
||||
|
||||
private onRoutesChanged() {
|
||||
const tree = readRoutes(this.el);
|
||||
this.routes = flattenRouterTree(tree);
|
||||
this.writeNavStateRoot(this.getPath(), RouterDirection.None);
|
||||
}
|
||||
|
||||
private historyDirection() {
|
||||
if (this.win.history.state === null) {
|
||||
this.state++;
|
||||
@@ -130,6 +113,14 @@ export class Router {
|
||||
}
|
||||
}
|
||||
|
||||
@Method()
|
||||
printDebug() {
|
||||
console.debug('CURRENT PATH', this.getPath());
|
||||
console.debug('PREVIOUS PATH', this.previousPath);
|
||||
printRoutes(this.routes);
|
||||
printRedirects(this.redirects);
|
||||
}
|
||||
|
||||
@Method()
|
||||
async navChanged(direction: RouterDirection): Promise<boolean> {
|
||||
if (this.busy) {
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { RouteChain } from './interface';
|
||||
import { RouteChain, RouteRedirect } from './interface';
|
||||
import { generatePath } from './path';
|
||||
|
||||
export function printRoutes(routes: RouteChain[]) {
|
||||
console.groupCollapsed(`[ion-core] registered ${routes.length} routes`);
|
||||
console.group(`[ion-core] ROUTES[${routes.length}]`);
|
||||
for (const chain of routes) {
|
||||
const path: string[] = [];
|
||||
chain.forEach(r => path.push(...r.path));
|
||||
@@ -11,3 +11,13 @@ export function printRoutes(routes: RouteChain[]) {
|
||||
}
|
||||
console.groupEnd();
|
||||
}
|
||||
|
||||
export function printRedirects(redirects: RouteRedirect[]) {
|
||||
console.group(`[ion-core] REDIRECTS[${redirects.length}]`);
|
||||
for (const redirect of redirects) {
|
||||
if (redirect.to) {
|
||||
console.debug('FROM: ', `$c ${generatePath(redirect.from)}`, 'font-weight: bold', ' TO: ', `$c ${generatePath(redirect.to)}`, 'font-weight: bold');
|
||||
}
|
||||
}
|
||||
console.groupEnd();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user