@esmx/router 3.0.0-rc.18 → 3.0.0-rc.19
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +1 -1
- package/README.md +70 -0
- package/README.zh-CN.md +70 -0
- package/dist/error.d.ts +23 -0
- package/dist/error.mjs +61 -0
- package/dist/increment-id.d.ts +7 -0
- package/dist/increment-id.mjs +11 -0
- package/dist/index.d.ts +5 -3
- package/dist/index.mjs +14 -3
- package/dist/index.test.mjs +8 -0
- package/dist/location.d.ts +15 -0
- package/dist/location.mjs +53 -0
- package/dist/location.test.d.ts +8 -0
- package/dist/location.test.mjs +370 -0
- package/dist/matcher.d.ts +3 -0
- package/dist/matcher.mjs +44 -0
- package/dist/matcher.test.mjs +1492 -0
- package/dist/micro-app.d.ts +18 -0
- package/dist/micro-app.dom.test.d.ts +1 -0
- package/dist/micro-app.dom.test.mjs +532 -0
- package/dist/micro-app.mjs +80 -0
- package/dist/navigation.d.ts +43 -0
- package/dist/navigation.mjs +143 -0
- package/dist/navigation.test.d.ts +1 -0
- package/dist/navigation.test.mjs +681 -0
- package/dist/options.d.ts +4 -0
- package/dist/options.mjs +88 -0
- package/dist/route-task.d.ts +40 -0
- package/dist/route-task.mjs +75 -0
- package/dist/route-task.test.d.ts +1 -0
- package/dist/route-task.test.mjs +673 -0
- package/dist/route-transition.d.ts +53 -0
- package/dist/route-transition.mjs +307 -0
- package/dist/route-transition.test.d.ts +1 -0
- package/dist/route-transition.test.mjs +146 -0
- package/dist/route.d.ts +72 -0
- package/dist/route.mjs +194 -0
- package/dist/route.test.d.ts +1 -0
- package/dist/route.test.mjs +1664 -0
- package/dist/router-back.test.d.ts +1 -0
- package/dist/router-back.test.mjs +361 -0
- package/dist/router-forward.test.d.ts +1 -0
- package/dist/router-forward.test.mjs +376 -0
- package/dist/router-go.test.d.ts +1 -0
- package/dist/router-go.test.mjs +73 -0
- package/dist/router-guards-cleanup.test.d.ts +1 -0
- package/dist/router-guards-cleanup.test.mjs +437 -0
- package/dist/router-link.d.ts +10 -0
- package/dist/router-link.mjs +126 -0
- package/dist/router-push.test.d.ts +1 -0
- package/dist/router-push.test.mjs +115 -0
- package/dist/router-replace.test.d.ts +1 -0
- package/dist/router-replace.test.mjs +114 -0
- package/dist/router-resolve.test.d.ts +1 -0
- package/dist/router-resolve.test.mjs +393 -0
- package/dist/router-restart-app.dom.test.d.ts +1 -0
- package/dist/router-restart-app.dom.test.mjs +616 -0
- package/dist/router-window-navigation.test.d.ts +1 -0
- package/dist/router-window-navigation.test.mjs +359 -0
- package/dist/router.d.ts +109 -102
- package/dist/router.mjs +260 -361
- package/dist/types.d.ts +246 -0
- package/dist/types.mjs +18 -0
- package/dist/util.d.ts +26 -0
- package/dist/util.mjs +53 -0
- package/dist/util.test.d.ts +1 -0
- package/dist/util.test.mjs +1020 -0
- package/package.json +10 -13
- package/src/error.ts +84 -0
- package/src/increment-id.ts +12 -0
- package/src/index.test.ts +9 -0
- package/src/index.ts +54 -3
- package/src/location.test.ts +406 -0
- package/src/location.ts +96 -0
- package/src/matcher.test.ts +1685 -0
- package/src/matcher.ts +59 -0
- package/src/micro-app.dom.test.ts +708 -0
- package/src/micro-app.ts +101 -0
- package/src/navigation.test.ts +858 -0
- package/src/navigation.ts +195 -0
- package/src/options.ts +131 -0
- package/src/route-task.test.ts +901 -0
- package/src/route-task.ts +105 -0
- package/src/route-transition.test.ts +178 -0
- package/src/route-transition.ts +425 -0
- package/src/route.test.ts +2014 -0
- package/src/route.ts +308 -0
- package/src/router-back.test.ts +487 -0
- package/src/router-forward.test.ts +506 -0
- package/src/router-go.test.ts +91 -0
- package/src/router-guards-cleanup.test.ts +595 -0
- package/src/router-link.ts +235 -0
- package/src/router-push.test.ts +140 -0
- package/src/router-replace.test.ts +139 -0
- package/src/router-resolve.test.ts +475 -0
- package/src/router-restart-app.dom.test.ts +783 -0
- package/src/router-window-navigation.test.ts +457 -0
- package/src/router.ts +289 -470
- package/src/types.ts +341 -0
- package/src/util.test.ts +1262 -0
- package/src/util.ts +116 -0
- package/dist/history/abstract.d.ts +0 -29
- package/dist/history/abstract.mjs +0 -107
- package/dist/history/base.d.ts +0 -79
- package/dist/history/base.mjs +0 -275
- package/dist/history/html.d.ts +0 -30
- package/dist/history/html.mjs +0 -183
- package/dist/history/index.d.ts +0 -7
- package/dist/history/index.mjs +0 -16
- package/dist/matcher/create-matcher.d.ts +0 -5
- package/dist/matcher/create-matcher.mjs +0 -218
- package/dist/matcher/create-matcher.spec.mjs +0 -0
- package/dist/matcher/index.d.ts +0 -1
- package/dist/matcher/index.mjs +0 -1
- package/dist/task-pipe/index.d.ts +0 -1
- package/dist/task-pipe/index.mjs +0 -1
- package/dist/task-pipe/task.d.ts +0 -30
- package/dist/task-pipe/task.mjs +0 -66
- package/dist/types/index.d.ts +0 -694
- package/dist/types/index.mjs +0 -6
- package/dist/utils/bom.d.ts +0 -5
- package/dist/utils/bom.mjs +0 -10
- package/dist/utils/encoding.d.ts +0 -48
- package/dist/utils/encoding.mjs +0 -44
- package/dist/utils/guards.d.ts +0 -9
- package/dist/utils/guards.mjs +0 -12
- package/dist/utils/index.d.ts +0 -7
- package/dist/utils/index.mjs +0 -27
- package/dist/utils/path.d.ts +0 -60
- package/dist/utils/path.mjs +0 -282
- package/dist/utils/path.spec.mjs +0 -27
- package/dist/utils/scroll.d.ts +0 -25
- package/dist/utils/scroll.mjs +0 -59
- package/dist/utils/utils.d.ts +0 -16
- package/dist/utils/utils.mjs +0 -11
- package/dist/utils/warn.d.ts +0 -2
- package/dist/utils/warn.mjs +0 -12
- package/src/history/abstract.ts +0 -149
- package/src/history/base.ts +0 -408
- package/src/history/html.ts +0 -228
- package/src/history/index.ts +0 -20
- package/src/matcher/create-matcher.spec.ts +0 -3
- package/src/matcher/create-matcher.ts +0 -292
- package/src/matcher/index.ts +0 -1
- package/src/task-pipe/index.ts +0 -1
- package/src/task-pipe/task.ts +0 -97
- package/src/types/index.ts +0 -858
- package/src/utils/bom.ts +0 -14
- package/src/utils/encoding.ts +0 -153
- package/src/utils/guards.ts +0 -25
- package/src/utils/index.ts +0 -27
- package/src/utils/path.spec.ts +0 -32
- package/src/utils/path.ts +0 -418
- package/src/utils/scroll.ts +0 -120
- package/src/utils/utils.ts +0 -30
- package/src/utils/warn.ts +0 -13
- /package/dist/{matcher/create-matcher.spec.d.ts → index.test.d.ts} +0 -0
- /package/dist/{utils/path.spec.d.ts → matcher.test.d.ts} +0 -0
package/src/router.ts
CHANGED
|
@@ -1,521 +1,340 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
type RouterScrollBehavior,
|
|
22
|
-
StateLayerConfigKey
|
|
1
|
+
import { LAYER_ID } from './increment-id';
|
|
2
|
+
import { MicroApp } from './micro-app';
|
|
3
|
+
import { Navigation } from './navigation';
|
|
4
|
+
import { parsedOptions } from './options';
|
|
5
|
+
import { Route } from './route';
|
|
6
|
+
import { RouteTransition } from './route-transition';
|
|
7
|
+
import { createLinkResolver } from './router-link';
|
|
8
|
+
import { RouteType, RouterMode } from './types';
|
|
9
|
+
import type {
|
|
10
|
+
RouteConfirmHook,
|
|
11
|
+
RouteLayerOptions,
|
|
12
|
+
RouteLayerResult,
|
|
13
|
+
RouteLocationInput,
|
|
14
|
+
RouteMatchType,
|
|
15
|
+
RouteNotifyHook,
|
|
16
|
+
RouteState,
|
|
17
|
+
RouterLinkProps,
|
|
18
|
+
RouterLinkResolved,
|
|
19
|
+
RouterOptions,
|
|
20
|
+
RouterParsedOptions
|
|
23
21
|
} from './types';
|
|
24
|
-
import {
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
/* 路由配置 */
|
|
43
|
-
options: RouterOptions;
|
|
44
|
-
|
|
45
|
-
/**
|
|
46
|
-
* 路由固定前置路径
|
|
47
|
-
* 需要注意的是如果使用函数返回 base,需要尽量保证相同的路径返回相同base
|
|
48
|
-
*/
|
|
49
|
-
base: RouterBase;
|
|
50
|
-
|
|
51
|
-
/* 路由模式 */
|
|
52
|
-
mode: RouterMode;
|
|
53
|
-
|
|
54
|
-
/* 路由匹配器 */
|
|
55
|
-
matcher: RouterMatcher;
|
|
56
|
-
|
|
57
|
-
/* 路由history类 */
|
|
58
|
-
history: RouterHistory;
|
|
59
|
-
|
|
60
|
-
/* 滚动行为 */
|
|
61
|
-
scrollBehavior: RouterScrollBehavior;
|
|
62
|
-
|
|
63
|
-
/* 当前路由信息 */
|
|
64
|
-
route: Route = {
|
|
65
|
-
href: '',
|
|
66
|
-
origin: '',
|
|
67
|
-
host: '',
|
|
68
|
-
protocol: '',
|
|
69
|
-
hostname: '',
|
|
70
|
-
port: '',
|
|
71
|
-
pathname: '',
|
|
72
|
-
search: '',
|
|
73
|
-
hash: '',
|
|
74
|
-
|
|
75
|
-
params: {},
|
|
76
|
-
query: {},
|
|
77
|
-
queryArray: {},
|
|
78
|
-
state: {},
|
|
79
|
-
meta: {},
|
|
80
|
-
base: '',
|
|
81
|
-
path: '',
|
|
82
|
-
fullPath: '',
|
|
83
|
-
matched: []
|
|
84
|
-
};
|
|
85
|
-
|
|
86
|
-
constructor(options: RouterOptions) {
|
|
87
|
-
this.options = options;
|
|
88
|
-
this.matcher = createRouterMatcher(options.routes || []);
|
|
89
|
-
|
|
90
|
-
this.mode =
|
|
91
|
-
options.mode ||
|
|
92
|
-
(inBrowser ? RouterMode.HISTORY : RouterMode.ABSTRACT);
|
|
93
|
-
|
|
94
|
-
this.base = options.base || '';
|
|
95
|
-
|
|
96
|
-
this.scrollBehavior =
|
|
97
|
-
options.scrollBehavior ||
|
|
98
|
-
((to, from, savedPosition) => {
|
|
99
|
-
if (savedPosition) return savedPosition;
|
|
100
|
-
return {
|
|
101
|
-
left: 0,
|
|
102
|
-
top: 0
|
|
103
|
-
};
|
|
104
|
-
});
|
|
105
|
-
|
|
106
|
-
this.history = createHistory({
|
|
107
|
-
router: this,
|
|
108
|
-
mode: this.mode
|
|
109
|
-
});
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
/* 更新路由 */
|
|
113
|
-
updateRoute(route: RouteRecord) {
|
|
114
|
-
const curAppType = this.route?.matched[0]?.appType;
|
|
115
|
-
const appType = route.matched[0]?.appType;
|
|
116
|
-
this.applyRoute(route);
|
|
117
|
-
|
|
118
|
-
const curRegisterConfig =
|
|
119
|
-
curAppType && this.registeredConfigMap[curAppType];
|
|
120
|
-
const registerConfig = appType && this.registeredConfigMap[appType];
|
|
121
|
-
|
|
122
|
-
if (registerConfig) {
|
|
123
|
-
const { mounted, generator } = registerConfig;
|
|
124
|
-
if (!mounted) {
|
|
125
|
-
registerConfig.config = generator(this);
|
|
126
|
-
registerConfig.config?.mount();
|
|
127
|
-
registerConfig.mounted = true;
|
|
128
|
-
|
|
129
|
-
this.layerMap[this.layerId] = {
|
|
130
|
-
router: this,
|
|
131
|
-
config: registerConfig.config,
|
|
132
|
-
destroyed: false
|
|
133
|
-
};
|
|
134
|
-
if (
|
|
135
|
-
!this.layerConfigList.find(
|
|
136
|
-
(item) => item.id === this.layerId
|
|
137
|
-
)
|
|
138
|
-
) {
|
|
139
|
-
this.layerConfigList.push({
|
|
140
|
-
id: this.layerId,
|
|
141
|
-
depth: 0
|
|
142
|
-
});
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
registerConfig.config?.updated();
|
|
22
|
+
import { isNotNullish, isPlainObject, isRouteMatched } from './util';
|
|
23
|
+
|
|
24
|
+
export class Router {
|
|
25
|
+
public readonly options: RouterOptions;
|
|
26
|
+
public readonly parsedOptions: RouterParsedOptions;
|
|
27
|
+
public readonly isLayer: boolean;
|
|
28
|
+
public readonly navigation: Navigation;
|
|
29
|
+
public readonly microApp: MicroApp = new MicroApp();
|
|
30
|
+
|
|
31
|
+
// Route transition manager
|
|
32
|
+
public readonly transition = new RouteTransition(this);
|
|
33
|
+
public get route() {
|
|
34
|
+
const route = this.transition.route;
|
|
35
|
+
if (route === null) {
|
|
36
|
+
throw new Error(
|
|
37
|
+
'No active route found. Please navigate to a route first using router.push() or router.replace().'
|
|
38
|
+
);
|
|
146
39
|
}
|
|
147
|
-
|
|
148
|
-
if (curAppType !== appType && curRegisterConfig) {
|
|
149
|
-
curRegisterConfig.config?.destroy();
|
|
150
|
-
curRegisterConfig.mounted = false;
|
|
151
|
-
}
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
/* 应用路由 */
|
|
155
|
-
protected applyRoute(route: RouteRecord) {
|
|
156
|
-
let url = '';
|
|
157
|
-
const { fullPath } = route;
|
|
158
|
-
if (inBrowser && !regexDomain.test(fullPath)) {
|
|
159
|
-
url = normalizePath(fullPath, location.origin);
|
|
160
|
-
} else {
|
|
161
|
-
url = normalizePath(fullPath);
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
const {
|
|
165
|
-
hash,
|
|
166
|
-
host,
|
|
167
|
-
hostname,
|
|
168
|
-
href,
|
|
169
|
-
origin,
|
|
170
|
-
pathname,
|
|
171
|
-
port,
|
|
172
|
-
protocol,
|
|
173
|
-
query
|
|
174
|
-
} = new URLParse(url);
|
|
175
|
-
Object.assign(
|
|
176
|
-
this.route,
|
|
177
|
-
{
|
|
178
|
-
href,
|
|
179
|
-
origin,
|
|
180
|
-
host,
|
|
181
|
-
protocol,
|
|
182
|
-
hostname,
|
|
183
|
-
port,
|
|
184
|
-
pathname,
|
|
185
|
-
search: query,
|
|
186
|
-
hash
|
|
187
|
-
},
|
|
188
|
-
route
|
|
189
|
-
);
|
|
40
|
+
return route;
|
|
190
41
|
}
|
|
191
42
|
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
return this.history.resolve(location);
|
|
43
|
+
public get root() {
|
|
44
|
+
return this.parsedOptions.root;
|
|
195
45
|
}
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
* 新增单个路由匹配规则
|
|
199
|
-
*/
|
|
200
|
-
// addRoutes(routes: RouteConfig[]) {
|
|
201
|
-
// this.matcher.addRoutes(routes);
|
|
202
|
-
// }
|
|
203
|
-
|
|
204
|
-
/**
|
|
205
|
-
* 新增多个路由匹配规则
|
|
206
|
-
*/
|
|
207
|
-
// addRoute(route: RouteConfig): void {
|
|
208
|
-
// this.matcher.addRoute(route);
|
|
209
|
-
// }
|
|
210
|
-
|
|
211
|
-
/* 初始化 */
|
|
212
|
-
async init(options: RouterInitOptions = {}) {
|
|
213
|
-
const { parent = null, route, replace = true } = options;
|
|
214
|
-
|
|
215
|
-
await this.history.init({
|
|
216
|
-
replace
|
|
217
|
-
});
|
|
218
|
-
|
|
219
|
-
const layerId = getLatestLayerId();
|
|
220
|
-
this.layerId = layerId;
|
|
221
|
-
let layerMap: RouterInstance['layerMap'] = {};
|
|
222
|
-
let layerConfigList: RouterInstance['layerConfigList'] = [];
|
|
223
|
-
if (parent && route) {
|
|
224
|
-
const appType = route.matched[0]?.appType;
|
|
225
|
-
if (!appType) return;
|
|
226
|
-
const registerConfig = parent.registeredConfigMap[appType];
|
|
227
|
-
if (!registerConfig) return;
|
|
228
|
-
|
|
229
|
-
parent.freeze();
|
|
230
|
-
this.registeredConfigMap = parent.registeredConfigMap;
|
|
231
|
-
const { generator } = registerConfig;
|
|
232
|
-
const config = generator(this);
|
|
233
|
-
config.mount();
|
|
234
|
-
config.updated();
|
|
235
|
-
layerMap = parent.layerMap;
|
|
236
|
-
|
|
237
|
-
layerMap[layerId] = {
|
|
238
|
-
router: this,
|
|
239
|
-
config,
|
|
240
|
-
destroyed: false
|
|
241
|
-
};
|
|
242
|
-
layerConfigList = parent.layerConfigList;
|
|
243
|
-
}
|
|
244
|
-
if (!layerConfigList.find((item) => item.id === layerId)) {
|
|
245
|
-
layerConfigList.push({
|
|
246
|
-
id: layerId,
|
|
247
|
-
depth: 0
|
|
248
|
-
});
|
|
249
|
-
}
|
|
250
|
-
this.parent = parent;
|
|
251
|
-
this.layerMap = layerMap;
|
|
252
|
-
this.layerConfigList = layerConfigList;
|
|
46
|
+
public get req() {
|
|
47
|
+
return this.parsedOptions.req ?? null;
|
|
253
48
|
}
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
* 卸载方法
|
|
257
|
-
*/
|
|
258
|
-
async destroy() {
|
|
259
|
-
// this.history.destroy();
|
|
49
|
+
public get res() {
|
|
50
|
+
return this.parsedOptions.res ?? null;
|
|
260
51
|
}
|
|
261
52
|
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
53
|
+
public constructor(options: RouterOptions) {
|
|
54
|
+
this.options = options;
|
|
55
|
+
this.parsedOptions = parsedOptions(options);
|
|
56
|
+
this.isLayer = this.parsedOptions.layer;
|
|
57
|
+
|
|
58
|
+
this.navigation = new Navigation(
|
|
59
|
+
this.parsedOptions,
|
|
60
|
+
(url: string, state: RouteState) => {
|
|
61
|
+
this.transition.to(RouteType.unknown, {
|
|
62
|
+
url,
|
|
63
|
+
state
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
);
|
|
274
67
|
}
|
|
275
68
|
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
beforeEach: NavigationGuard[];
|
|
279
|
-
afterEach: NavigationGuardAfter[];
|
|
280
|
-
} = {
|
|
281
|
-
beforeEach: [],
|
|
282
|
-
afterEach: []
|
|
283
|
-
};
|
|
284
|
-
|
|
285
|
-
/* 注册全局路由前置守卫 */
|
|
286
|
-
beforeEach(guard: NavigationGuard) {
|
|
287
|
-
this.guards.beforeEach.push(guard);
|
|
69
|
+
public push(toInput: RouteLocationInput): Promise<Route> {
|
|
70
|
+
return this.transition.to(RouteType.push, toInput);
|
|
288
71
|
}
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
unBindBeforeEach(guard: NavigationGuard) {
|
|
292
|
-
const i = this.guards.beforeEach.findIndex((item) => item === guard);
|
|
293
|
-
this.guards.beforeEach.splice(i, 1);
|
|
72
|
+
public replace(toInput: RouteLocationInput): Promise<Route> {
|
|
73
|
+
return this.transition.to(RouteType.replace, toInput);
|
|
294
74
|
}
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
afterEach(guard: NavigationGuardAfter) {
|
|
298
|
-
this.guards.afterEach.push(guard);
|
|
75
|
+
public pushWindow(toInput: RouteLocationInput): Promise<Route> {
|
|
76
|
+
return this.transition.to(RouteType.pushWindow, toInput);
|
|
299
77
|
}
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
unBindAfterEach(guard: NavigationGuardAfter) {
|
|
303
|
-
const i = this.guards.afterEach.findIndex((item) => item === guard);
|
|
304
|
-
this.guards.afterEach.splice(i, 1);
|
|
78
|
+
public replaceWindow(toInput: RouteLocationInput): Promise<Route> {
|
|
79
|
+
return this.transition.to(RouteType.replaceWindow, toInput);
|
|
305
80
|
}
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
81
|
+
public restartApp(toInput?: RouteLocationInput): Promise<Route> {
|
|
82
|
+
return this.transition.to(
|
|
83
|
+
RouteType.restartApp,
|
|
84
|
+
toInput ?? this.route.url.href
|
|
85
|
+
);
|
|
310
86
|
}
|
|
311
87
|
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
88
|
+
public async back(): Promise<Route | null> {
|
|
89
|
+
const result = await this.navigation.go(-1);
|
|
90
|
+
if (result === null) {
|
|
91
|
+
this.parsedOptions.handleBackBoundary(this);
|
|
92
|
+
return null;
|
|
93
|
+
}
|
|
94
|
+
return this.transition.to(RouteType.back, {
|
|
95
|
+
url: result.url,
|
|
96
|
+
state: result.state
|
|
97
|
+
});
|
|
315
98
|
}
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
/**
|
|
328
|
-
* 路由弹层id
|
|
329
|
-
*/
|
|
330
|
-
id: number;
|
|
331
|
-
/**
|
|
332
|
-
* 路由弹层深度
|
|
333
|
-
*/
|
|
334
|
-
depth: number;
|
|
335
|
-
}> = [];
|
|
336
|
-
|
|
337
|
-
/**
|
|
338
|
-
* 路由弹层id与路由实例的map
|
|
339
|
-
*/
|
|
340
|
-
layerMap: Record<
|
|
341
|
-
number,
|
|
342
|
-
{
|
|
343
|
-
router: RouterInstance;
|
|
344
|
-
config: RegisteredConfig;
|
|
345
|
-
destroyed: boolean;
|
|
99
|
+
public async go(index: number): Promise<Route | null> {
|
|
100
|
+
// go(0) refreshes the page in browser, but we return null directly in router
|
|
101
|
+
if (index === 0) return null;
|
|
102
|
+
|
|
103
|
+
const result = await this.navigation.go(index);
|
|
104
|
+
if (result === null) {
|
|
105
|
+
// Call handleBackBoundary when backward navigation has no response
|
|
106
|
+
if (index < 0) {
|
|
107
|
+
this.parsedOptions.handleBackBoundary(this);
|
|
108
|
+
}
|
|
109
|
+
return null;
|
|
346
110
|
}
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
111
|
+
return this.transition.to(RouteType.go, {
|
|
112
|
+
url: result.url,
|
|
113
|
+
state: result.state
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
public async forward(): Promise<Route | null> {
|
|
117
|
+
const result = await this.navigation.go(1);
|
|
118
|
+
if (result === null) return null;
|
|
119
|
+
return this.transition.to(RouteType.forward, {
|
|
120
|
+
url: result.url,
|
|
121
|
+
state: result.state
|
|
122
|
+
});
|
|
123
|
+
}
|
|
353
124
|
|
|
354
125
|
/**
|
|
355
|
-
*
|
|
126
|
+
* Parse route location without performing actual navigation
|
|
127
|
+
*
|
|
128
|
+
* This method is used to parse route configuration and return the corresponding route object,
|
|
129
|
+
* but does not trigger actual page navigation. It is mainly used for the following scenarios:
|
|
130
|
+
* - Generate link URLs without jumping
|
|
131
|
+
* - Pre-check route matching
|
|
132
|
+
* - Get route parameters, meta information, etc.
|
|
133
|
+
* - Test the validity of route configuration
|
|
134
|
+
*
|
|
135
|
+
* @param toInput Target route location, can be a string path or route configuration object
|
|
136
|
+
* @returns Parsed route object containing complete route information
|
|
137
|
+
*
|
|
138
|
+
* @example
|
|
139
|
+
* ```typescript
|
|
140
|
+
* // Parse string path
|
|
141
|
+
* const route = router.resolve('/user/123');
|
|
142
|
+
* const url = route.url.href; // Get complete URL
|
|
143
|
+
*
|
|
144
|
+
* // Parse named route
|
|
145
|
+
* const userRoute = router.resolve({
|
|
146
|
+
* name: 'user',
|
|
147
|
+
* params: { id: '123' }
|
|
148
|
+
* });
|
|
149
|
+
* console.log(userRoute.params.id); // '123'
|
|
150
|
+
*
|
|
151
|
+
* // Check route validity
|
|
152
|
+
* const testRoute = router.resolve('/some/path');
|
|
153
|
+
* if (testRoute.matched.length > 0) {
|
|
154
|
+
* // Route matched successfully
|
|
155
|
+
* }
|
|
156
|
+
* ```
|
|
356
157
|
*/
|
|
357
|
-
|
|
358
|
-
|
|
158
|
+
public resolve(toInput: RouteLocationInput, toType?: RouteType): Route {
|
|
159
|
+
return new Route({
|
|
160
|
+
options: this.parsedOptions,
|
|
161
|
+
toType,
|
|
162
|
+
toInput,
|
|
163
|
+
from: this.transition.route?.url ?? null
|
|
164
|
+
});
|
|
359
165
|
}
|
|
360
166
|
|
|
361
167
|
/**
|
|
362
|
-
*
|
|
168
|
+
* Check if the route matches the current route
|
|
169
|
+
*
|
|
170
|
+
* @param targetRoute Target route object to compare
|
|
171
|
+
* @param matchType Match type
|
|
172
|
+
* - 'route': Route-level matching, compare if route configurations are the same
|
|
173
|
+
* - 'exact': Exact matching, compare if paths are completely the same
|
|
174
|
+
* - 'include': Include matching, check if current path contains target path
|
|
175
|
+
* @returns Whether it matches
|
|
363
176
|
*/
|
|
364
|
-
|
|
365
|
-
|
|
177
|
+
public isRouteMatched(
|
|
178
|
+
targetRoute: Route,
|
|
179
|
+
matchType: RouteMatchType = 'include'
|
|
180
|
+
): boolean {
|
|
181
|
+
const currentRoute = this.transition.route;
|
|
182
|
+
if (!currentRoute) return false;
|
|
183
|
+
|
|
184
|
+
return isRouteMatched(currentRoute, targetRoute, matchType);
|
|
366
185
|
}
|
|
367
186
|
|
|
368
187
|
/**
|
|
369
|
-
*
|
|
370
|
-
*
|
|
188
|
+
* Resolve router link configuration and return complete link data
|
|
189
|
+
*
|
|
190
|
+
* This method analyzes router link properties and returns a comprehensive
|
|
191
|
+
* link resolution result including route information, navigation functions,
|
|
192
|
+
* HTML attributes, and event handlers. It's primarily used for:
|
|
193
|
+
* - Framework-agnostic link component implementation
|
|
194
|
+
* - Generating link attributes and navigation handlers
|
|
195
|
+
* - Computing active states and CSS classes
|
|
196
|
+
* - Creating event handlers for different frameworks
|
|
197
|
+
*
|
|
198
|
+
* @param props Router link configuration properties
|
|
199
|
+
* @returns Complete link resolution result with all necessary data
|
|
200
|
+
*
|
|
201
|
+
* @example
|
|
202
|
+
* ```typescript
|
|
203
|
+
* // Basic link resolution
|
|
204
|
+
* const linkData = router.resolveLink({
|
|
205
|
+
* to: '/user/123',
|
|
206
|
+
* type: 'push'
|
|
207
|
+
* });
|
|
208
|
+
*
|
|
209
|
+
* // Access resolved data
|
|
210
|
+
* console.log(linkData.route.path); // '/user/123'
|
|
211
|
+
* console.log(linkData.attributes.href); // Full href URL
|
|
212
|
+
* console.log(linkData.isActive); // Active state
|
|
213
|
+
*
|
|
214
|
+
* // Use navigation function
|
|
215
|
+
* linkData.navigate(); // Programmatic navigation
|
|
216
|
+
*
|
|
217
|
+
* // Get event handlers for React
|
|
218
|
+
* const handlers = linkData.getEventHandlers(name => `on${name.charAt(0).toUpperCase() + name.slice(1)}`);
|
|
219
|
+
* // handlers.onClick for React
|
|
220
|
+
* ```
|
|
371
221
|
*/
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
const route = this.resolve(location);
|
|
375
|
-
if (route.fullPath === this.route.fullPath) return;
|
|
376
|
-
if (!inBrowser) {
|
|
377
|
-
this.push(location);
|
|
378
|
-
return;
|
|
379
|
-
}
|
|
380
|
-
const router = createRouter({
|
|
381
|
-
...this.options,
|
|
382
|
-
initUrl: route.fullPath
|
|
383
|
-
});
|
|
384
|
-
await router.init({ parent: this, route, replace: false });
|
|
222
|
+
public resolveLink(props: RouterLinkProps): RouterLinkResolved {
|
|
223
|
+
return createLinkResolver(this, props);
|
|
385
224
|
}
|
|
386
225
|
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
checkLayerState(state: HistoryState) {
|
|
393
|
-
// state 中存放的 layerConfig 配置
|
|
394
|
-
const stateLayerConfigList =
|
|
395
|
-
(state[StateLayerConfigKey] as typeof this.layerConfigList) || [];
|
|
226
|
+
public async createLayer(
|
|
227
|
+
toInput: RouteLocationInput
|
|
228
|
+
): Promise<{ promise: Promise<RouteLayerResult>; router: Router }> {
|
|
229
|
+
const layerOptions: RouteLayerOptions =
|
|
230
|
+
(isPlainObject(toInput) ? toInput.layer : null) || {};
|
|
396
231
|
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
// state中存放的可用的 layerId 列表
|
|
400
|
-
const stateLayerIdList = stateLayerConfigList
|
|
401
|
-
.map(({ id }) => id)
|
|
402
|
-
.filter((id) => {
|
|
403
|
-
return layerConfigList.includes(id);
|
|
404
|
-
});
|
|
405
|
-
if (stateLayerIdList.length === 0) {
|
|
406
|
-
// 没有可用的 layerId 列表时跳出
|
|
407
|
-
return false;
|
|
408
|
-
}
|
|
409
|
-
if (
|
|
410
|
-
stateLayerIdList.length === 1 &&
|
|
411
|
-
stateLayerIdList[0] === this.layerId
|
|
412
|
-
) {
|
|
413
|
-
// 只有一个可用的 layerId 并且就是当前的layerId时跳出
|
|
414
|
-
return false;
|
|
415
|
-
}
|
|
232
|
+
const zIndex =
|
|
233
|
+
layerOptions.zIndex ?? this.parsedOptions.zIndex + LAYER_ID.next();
|
|
416
234
|
|
|
417
|
-
|
|
418
|
-
const
|
|
419
|
-
|
|
420
|
-
if (stateLayerIdList.includes(Number(key))) {
|
|
421
|
-
if (value.destroyed) {
|
|
422
|
-
createList.push(Number(key));
|
|
423
|
-
}
|
|
424
|
-
} else {
|
|
425
|
-
destroyList.push(Number(key));
|
|
426
|
-
}
|
|
235
|
+
let promiseResolve: (result: RouteLayerResult) => void;
|
|
236
|
+
const promise = new Promise<RouteLayerResult>((resolve) => {
|
|
237
|
+
promiseResolve = resolve;
|
|
427
238
|
});
|
|
428
|
-
if (createList.length === 0 && destroyList.length === 0) {
|
|
429
|
-
// 没有需要创建的 layerId 列表 并且 没有需要销毁的 layerId 列表时跳出
|
|
430
|
-
return false;
|
|
431
|
-
}
|
|
432
239
|
|
|
433
|
-
const
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
240
|
+
const router = new Router({
|
|
241
|
+
...this.options,
|
|
242
|
+
mode: RouterMode.memory,
|
|
243
|
+
rootStyle: {
|
|
244
|
+
position: 'fixed',
|
|
245
|
+
top: '0',
|
|
246
|
+
left: '0',
|
|
247
|
+
width: '100%',
|
|
248
|
+
height: '100%',
|
|
249
|
+
zIndex: String(zIndex),
|
|
250
|
+
background: 'rgba(0,0,0,.6)',
|
|
251
|
+
display: 'flex',
|
|
252
|
+
alignItems: 'center',
|
|
253
|
+
justifyContent: 'center'
|
|
254
|
+
},
|
|
255
|
+
root: undefined,
|
|
256
|
+
...layerOptions.routerOptions,
|
|
257
|
+
handleBackBoundary(router) {
|
|
449
258
|
router.destroy();
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
259
|
+
promiseResolve({
|
|
260
|
+
type: 'close',
|
|
261
|
+
route: router.route
|
|
262
|
+
});
|
|
263
|
+
},
|
|
264
|
+
handleLayerClose(router, data) {
|
|
265
|
+
router.destroy();
|
|
266
|
+
if (isNotNullish(data)) {
|
|
267
|
+
promiseResolve({
|
|
268
|
+
type: 'success',
|
|
269
|
+
route: router.route,
|
|
270
|
+
data
|
|
271
|
+
});
|
|
272
|
+
} else {
|
|
273
|
+
promiseResolve({
|
|
274
|
+
type: 'close',
|
|
275
|
+
route: router.route
|
|
276
|
+
});
|
|
277
|
+
}
|
|
278
|
+
},
|
|
279
|
+
layer: true
|
|
453
280
|
});
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
if (
|
|
458
|
-
const
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
281
|
+
await router.replace(toInput);
|
|
282
|
+
|
|
283
|
+
router.afterEach((to, from) => {
|
|
284
|
+
if (layerOptions.shouldClose) {
|
|
285
|
+
const result = layerOptions.shouldClose(to, from, router);
|
|
286
|
+
if (result === false) {
|
|
287
|
+
router.destroy();
|
|
288
|
+
promiseResolve({
|
|
289
|
+
type: 'push',
|
|
290
|
+
route: to
|
|
291
|
+
});
|
|
292
|
+
}
|
|
462
293
|
}
|
|
463
294
|
});
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
if (layerConfig) layerConfig.depth++;
|
|
474
|
-
const stateConfigList = this.layerConfigList.filter(({ id }) => {
|
|
475
|
-
return !this.layerMap[id]?.destroyed;
|
|
476
|
-
});
|
|
477
|
-
const state = {
|
|
478
|
-
...history.state,
|
|
479
|
-
[StateLayerConfigKey]: stateConfigList
|
|
295
|
+
if (layerOptions.push) {
|
|
296
|
+
router.navigation.pushHistoryState(
|
|
297
|
+
router.route.state,
|
|
298
|
+
router.route.url
|
|
299
|
+
);
|
|
300
|
+
}
|
|
301
|
+
return {
|
|
302
|
+
promise,
|
|
303
|
+
router
|
|
480
304
|
};
|
|
481
|
-
window.history.replaceState(state, '', route.fullPath);
|
|
482
305
|
}
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
this.history.pushWindow(location);
|
|
306
|
+
public async pushLayer(
|
|
307
|
+
toInput: RouteLocationInput
|
|
308
|
+
): Promise<RouteLayerResult> {
|
|
309
|
+
const result = await this.transition.to(RouteType.pushLayer, toInput);
|
|
310
|
+
return result.handleResult as RouteLayerResult;
|
|
489
311
|
}
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
*/
|
|
494
|
-
replaceWindow(location: RouterRawLocation) {
|
|
495
|
-
this.history.replaceWindow(location);
|
|
312
|
+
public closeLayer(data?: any) {
|
|
313
|
+
if (!this.isLayer) return;
|
|
314
|
+
this.parsedOptions.handleLayerClose(this, data);
|
|
496
315
|
}
|
|
497
316
|
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
317
|
+
public async renderToString(throwError = false): Promise<string | null> {
|
|
318
|
+
try {
|
|
319
|
+
const result = await this.microApp.app?.renderToString?.();
|
|
320
|
+
return result ?? null;
|
|
321
|
+
} catch (e) {
|
|
322
|
+
if (throwError) throw e;
|
|
323
|
+
else console.error(e);
|
|
324
|
+
return null;
|
|
325
|
+
}
|
|
501
326
|
}
|
|
502
327
|
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
this.history.forward();
|
|
328
|
+
public beforeEach(guard: RouteConfirmHook): () => void {
|
|
329
|
+
return this.transition.beforeEach(guard);
|
|
506
330
|
}
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
back() {
|
|
510
|
-
this.history.back();
|
|
331
|
+
public afterEach(guard: RouteNotifyHook): () => void {
|
|
332
|
+
return this.transition.afterEach(guard);
|
|
511
333
|
}
|
|
512
334
|
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
335
|
+
public destroy() {
|
|
336
|
+
this.transition.destroy();
|
|
337
|
+
this.navigation.destroy();
|
|
338
|
+
this.microApp.destroy();
|
|
516
339
|
}
|
|
517
340
|
}
|
|
518
|
-
|
|
519
|
-
export function createRouter(options: RouterOptions): RouterInstance {
|
|
520
|
-
return new Router(options);
|
|
521
|
-
}
|