@esmx/router 3.0.0-rc.17 → 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 -22
- 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/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 -281
- 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 -293
- 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/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 -417
- 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/history/base.ts
DELETED
|
@@ -1,408 +0,0 @@
|
|
|
1
|
-
import { type Tasks, createTasks } from '../task-pipe';
|
|
2
|
-
import type {
|
|
3
|
-
Awaitable,
|
|
4
|
-
NavigationGuard,
|
|
5
|
-
NavigationGuardAfter,
|
|
6
|
-
RouteRecord,
|
|
7
|
-
RouterHistory,
|
|
8
|
-
RouterInstance,
|
|
9
|
-
RouterRawLocation
|
|
10
|
-
} from '../types';
|
|
11
|
-
import {
|
|
12
|
-
isESModule,
|
|
13
|
-
isEqualRoute,
|
|
14
|
-
isSameRoute,
|
|
15
|
-
normalizeLocation,
|
|
16
|
-
stringifyPath
|
|
17
|
-
} from '../utils';
|
|
18
|
-
|
|
19
|
-
/**
|
|
20
|
-
* 创建一个路由记录
|
|
21
|
-
*/
|
|
22
|
-
function createRouteRecord(route: Partial<RouteRecord> = {}): RouteRecord {
|
|
23
|
-
return {
|
|
24
|
-
base: '',
|
|
25
|
-
path: '/',
|
|
26
|
-
fullPath: '/',
|
|
27
|
-
meta: {},
|
|
28
|
-
matched: [],
|
|
29
|
-
query: {},
|
|
30
|
-
queryArray: {},
|
|
31
|
-
params: {},
|
|
32
|
-
hash: '',
|
|
33
|
-
state: {},
|
|
34
|
-
...route
|
|
35
|
-
};
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
export abstract class BaseRouterHistory implements RouterHistory {
|
|
39
|
-
/**
|
|
40
|
-
* 路由类实例
|
|
41
|
-
*/
|
|
42
|
-
public router: RouterInstance;
|
|
43
|
-
|
|
44
|
-
/**
|
|
45
|
-
* 路由是否冻结
|
|
46
|
-
*/
|
|
47
|
-
public get isFrozen() {
|
|
48
|
-
return this.router.isFrozen;
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
/**
|
|
52
|
-
* 匹配的当前路由
|
|
53
|
-
*/
|
|
54
|
-
public current: RouteRecord = createRouteRecord();
|
|
55
|
-
|
|
56
|
-
constructor(router: RouterInstance) {
|
|
57
|
-
this.router = router;
|
|
58
|
-
Object.defineProperty(this, 'router', {
|
|
59
|
-
enumerable: false
|
|
60
|
-
});
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
/**
|
|
64
|
-
* 更新当前路由
|
|
65
|
-
*/
|
|
66
|
-
updateRoute(route: RouteRecord) {
|
|
67
|
-
this.current = route;
|
|
68
|
-
this.router.updateRoute(route);
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
/**
|
|
72
|
-
* 解析路由
|
|
73
|
-
*/
|
|
74
|
-
resolve(location: RouterRawLocation): RouteRecord {
|
|
75
|
-
const rawLocation =
|
|
76
|
-
typeof location === 'string' ? { path: location } : location;
|
|
77
|
-
if (rawLocation.path === undefined) {
|
|
78
|
-
rawLocation.path = this.current.fullPath;
|
|
79
|
-
}
|
|
80
|
-
const { base, ...normalizedLocation } = normalizeLocation(
|
|
81
|
-
rawLocation,
|
|
82
|
-
this.router.base
|
|
83
|
-
);
|
|
84
|
-
|
|
85
|
-
// 匹配成功则返回匹配值
|
|
86
|
-
const matcher = this.router.matcher.match(normalizedLocation, { base });
|
|
87
|
-
if (matcher) {
|
|
88
|
-
return matcher;
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
// 匹配失败则返回目标路径
|
|
92
|
-
const {
|
|
93
|
-
path = '',
|
|
94
|
-
params = {},
|
|
95
|
-
query = {},
|
|
96
|
-
queryArray = {},
|
|
97
|
-
hash = '',
|
|
98
|
-
state = {}
|
|
99
|
-
} = normalizedLocation;
|
|
100
|
-
const route = createRouteRecord({
|
|
101
|
-
base,
|
|
102
|
-
fullPath: stringifyPath({
|
|
103
|
-
pathname: path,
|
|
104
|
-
query,
|
|
105
|
-
queryArray,
|
|
106
|
-
hash
|
|
107
|
-
}),
|
|
108
|
-
path,
|
|
109
|
-
params,
|
|
110
|
-
query,
|
|
111
|
-
queryArray,
|
|
112
|
-
hash,
|
|
113
|
-
state
|
|
114
|
-
});
|
|
115
|
-
return route;
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
/**
|
|
119
|
-
* 核心跳转方法
|
|
120
|
-
*/
|
|
121
|
-
async transitionTo(
|
|
122
|
-
location: RouterRawLocation,
|
|
123
|
-
onComplete?: (route: RouteRecord) => void
|
|
124
|
-
) {
|
|
125
|
-
if (this.isFrozen) return;
|
|
126
|
-
// 寻找即将跳转路径匹配到的路由对象
|
|
127
|
-
const route = this.resolve(location);
|
|
128
|
-
|
|
129
|
-
this.abortTask();
|
|
130
|
-
|
|
131
|
-
// 禁止重复跳转
|
|
132
|
-
if (isEqualRoute(this.current, route)) {
|
|
133
|
-
return;
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
await this.runTask(this.current, route, onComplete);
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
/**
|
|
140
|
-
* TODO 逻辑解耦,抽离到task
|
|
141
|
-
* 重定向方法
|
|
142
|
-
*/
|
|
143
|
-
async redirectTo(
|
|
144
|
-
location: RouterRawLocation,
|
|
145
|
-
from: RouteRecord,
|
|
146
|
-
onComplete?: (route: RouteRecord) => void
|
|
147
|
-
) {
|
|
148
|
-
// 寻找即将跳转路径匹配到的路由对象
|
|
149
|
-
const route = this.resolve(location);
|
|
150
|
-
this.abortTask();
|
|
151
|
-
|
|
152
|
-
// 禁止重复跳转
|
|
153
|
-
if (isEqualRoute(this.current, route)) {
|
|
154
|
-
return;
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
await this.runTask(
|
|
158
|
-
this.current,
|
|
159
|
-
{
|
|
160
|
-
...route,
|
|
161
|
-
redirectedFrom: from
|
|
162
|
-
},
|
|
163
|
-
onComplete
|
|
164
|
-
);
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
/* 当前执行的任务 */
|
|
168
|
-
tasks: Tasks | null = null;
|
|
169
|
-
|
|
170
|
-
/* 取消任务 */
|
|
171
|
-
async abortTask() {
|
|
172
|
-
this.tasks?.abort();
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
/**
|
|
176
|
-
* 执行任务
|
|
177
|
-
* 任务分为三部分: 前置守卫(beforeEach、beforeEnter、beforeUpdate、beforeLeave)、加载路由(loadRoute)、后置守卫(afterEach)
|
|
178
|
-
* 根据触发方式不同,执行顺序分别为:
|
|
179
|
-
* 进入路由时: beforeEach -> beforeEnter -> loadRoute -> afterEach
|
|
180
|
-
* 更新路由时: beforeEach -> beforeUpdate -> afterEach
|
|
181
|
-
* 离开路由进入新路由时: beforeLeave -> beforeEach -> beforeEnter -> loadRoute -> afterEach
|
|
182
|
-
* @param from
|
|
183
|
-
* @param to
|
|
184
|
-
*/
|
|
185
|
-
async runTask(
|
|
186
|
-
from: RouteRecord,
|
|
187
|
-
to: RouteRecord,
|
|
188
|
-
onComplete?: (route: RouteRecord) => void
|
|
189
|
-
) {
|
|
190
|
-
const {
|
|
191
|
-
beforeEach,
|
|
192
|
-
beforeEnter,
|
|
193
|
-
beforeUpdate,
|
|
194
|
-
beforeLeave,
|
|
195
|
-
afterEach,
|
|
196
|
-
loadRoute
|
|
197
|
-
} = getNavigationHooks(this.router, from, to);
|
|
198
|
-
|
|
199
|
-
/* 前置钩子任务 */
|
|
200
|
-
const guardBeforeTasks: Tasks<NavigationGuard> = createTasks();
|
|
201
|
-
|
|
202
|
-
/* 后置钩子任务 */
|
|
203
|
-
const guardAfterTasks: Tasks<NavigationGuardAfter> =
|
|
204
|
-
createTasks<NavigationGuardAfter>();
|
|
205
|
-
|
|
206
|
-
/* 加载路由任务 */
|
|
207
|
-
const loadRouteTasks: Tasks<() => Awaitable<any>> =
|
|
208
|
-
createTasks<() => Awaitable<any>>();
|
|
209
|
-
|
|
210
|
-
if (isSameRoute(from, to)) {
|
|
211
|
-
// from 和 to 是相同路由说明为更新路由
|
|
212
|
-
guardBeforeTasks.add([...beforeEach, ...beforeUpdate]);
|
|
213
|
-
|
|
214
|
-
guardAfterTasks.add(afterEach);
|
|
215
|
-
} else {
|
|
216
|
-
// 反之为进入新路由
|
|
217
|
-
guardBeforeTasks.add([
|
|
218
|
-
...beforeLeave,
|
|
219
|
-
...beforeEach,
|
|
220
|
-
...beforeEnter
|
|
221
|
-
]);
|
|
222
|
-
loadRouteTasks.add(loadRoute);
|
|
223
|
-
|
|
224
|
-
guardAfterTasks.add(afterEach);
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
this.tasks = guardBeforeTasks;
|
|
228
|
-
await guardBeforeTasks.run({
|
|
229
|
-
cb: async (res) => {
|
|
230
|
-
switch (typeof res) {
|
|
231
|
-
case 'boolean':
|
|
232
|
-
if (!res) {
|
|
233
|
-
this.tasks?.abort();
|
|
234
|
-
}
|
|
235
|
-
break;
|
|
236
|
-
|
|
237
|
-
case 'undefined':
|
|
238
|
-
break;
|
|
239
|
-
|
|
240
|
-
default:
|
|
241
|
-
await this.redirectTo(res, from, onComplete);
|
|
242
|
-
break;
|
|
243
|
-
}
|
|
244
|
-
},
|
|
245
|
-
final: async () => {
|
|
246
|
-
this.tasks = loadRouteTasks;
|
|
247
|
-
await loadRouteTasks.run();
|
|
248
|
-
}
|
|
249
|
-
});
|
|
250
|
-
|
|
251
|
-
if (this.tasks?.status === 'finished') {
|
|
252
|
-
this.tasks = null;
|
|
253
|
-
guardAfterTasks.run();
|
|
254
|
-
|
|
255
|
-
onComplete && onComplete(to);
|
|
256
|
-
this.updateRoute(to);
|
|
257
|
-
}
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
/**
|
|
261
|
-
* 新开浏览器窗口的方法,在服务端会调用 push 作为替代
|
|
262
|
-
*/
|
|
263
|
-
abstract pushWindow(location: RouterRawLocation): void;
|
|
264
|
-
|
|
265
|
-
/**
|
|
266
|
-
* 替换当前浏览器窗口的方法,在服务端会调用 replace 作为替代
|
|
267
|
-
*/
|
|
268
|
-
abstract replaceWindow(location: RouterRawLocation): void;
|
|
269
|
-
|
|
270
|
-
/**
|
|
271
|
-
* 跳转方法,会创建新的历史纪录
|
|
272
|
-
*/
|
|
273
|
-
abstract push(location: RouterRawLocation): Promise<void>;
|
|
274
|
-
|
|
275
|
-
/**
|
|
276
|
-
* 跳转方法,替换当前历史记录
|
|
277
|
-
*/
|
|
278
|
-
abstract replace(location: RouterRawLocation): Promise<void>;
|
|
279
|
-
|
|
280
|
-
/**
|
|
281
|
-
* 路由移动到指定历史记录方法
|
|
282
|
-
*/
|
|
283
|
-
abstract go(delta: number): void;
|
|
284
|
-
|
|
285
|
-
/* 路由历史记录前进方法 */
|
|
286
|
-
abstract forward(): void;
|
|
287
|
-
|
|
288
|
-
/* 路由历史记录后退方法 */
|
|
289
|
-
abstract back(): void;
|
|
290
|
-
|
|
291
|
-
/**
|
|
292
|
-
* 初始化方法
|
|
293
|
-
*/
|
|
294
|
-
abstract init(params?: { replace?: boolean }): Promise<void>;
|
|
295
|
-
|
|
296
|
-
/**
|
|
297
|
-
* 卸载方法
|
|
298
|
-
*/
|
|
299
|
-
abstract destroy(): void;
|
|
300
|
-
}
|
|
301
|
-
|
|
302
|
-
/**
|
|
303
|
-
* 获取路由导航钩子
|
|
304
|
-
* 路由守卫钩子时顺序执行的,但是加载路由的钩子不依赖顺序
|
|
305
|
-
*/
|
|
306
|
-
function getNavigationHooks(
|
|
307
|
-
router: RouterInstance,
|
|
308
|
-
from: RouteRecord,
|
|
309
|
-
to: RouteRecord
|
|
310
|
-
): {
|
|
311
|
-
beforeEach: NavigationGuard[];
|
|
312
|
-
afterEach: NavigationGuardAfter[];
|
|
313
|
-
beforeEnter: NavigationGuard[];
|
|
314
|
-
beforeUpdate: NavigationGuard[];
|
|
315
|
-
beforeLeave: NavigationGuard[];
|
|
316
|
-
loadRoute: Array<() => Promise<any>>;
|
|
317
|
-
} {
|
|
318
|
-
const beforeEach = router.guards.beforeEach.map((guard) => {
|
|
319
|
-
return () => {
|
|
320
|
-
return guard(from, to);
|
|
321
|
-
};
|
|
322
|
-
});
|
|
323
|
-
const afterEach = router.guards.afterEach.map((guard) => {
|
|
324
|
-
return () => {
|
|
325
|
-
return guard(from, to);
|
|
326
|
-
};
|
|
327
|
-
});
|
|
328
|
-
|
|
329
|
-
const { beforeLeave } = from.matched.reduce<{
|
|
330
|
-
beforeLeave: NavigationGuard[];
|
|
331
|
-
}>(
|
|
332
|
-
(acc, { beforeLeave }) => {
|
|
333
|
-
if (beforeLeave) {
|
|
334
|
-
acc.beforeLeave.unshift(() => {
|
|
335
|
-
return beforeLeave(from, to);
|
|
336
|
-
});
|
|
337
|
-
}
|
|
338
|
-
return acc;
|
|
339
|
-
},
|
|
340
|
-
{
|
|
341
|
-
beforeLeave: []
|
|
342
|
-
}
|
|
343
|
-
);
|
|
344
|
-
|
|
345
|
-
const { beforeEnter, beforeUpdate } = to.matched.reduce<{
|
|
346
|
-
beforeEnter: NavigationGuard[];
|
|
347
|
-
beforeUpdate: NavigationGuard[];
|
|
348
|
-
}>(
|
|
349
|
-
(acc, { beforeEnter, beforeUpdate }) => {
|
|
350
|
-
if (beforeEnter) {
|
|
351
|
-
acc.beforeEnter.push(() => {
|
|
352
|
-
return beforeEnter(from, to);
|
|
353
|
-
});
|
|
354
|
-
}
|
|
355
|
-
|
|
356
|
-
if (beforeUpdate) {
|
|
357
|
-
acc.beforeUpdate.push(() => {
|
|
358
|
-
return beforeUpdate(from, to);
|
|
359
|
-
});
|
|
360
|
-
}
|
|
361
|
-
return acc;
|
|
362
|
-
},
|
|
363
|
-
{
|
|
364
|
-
beforeEnter: [],
|
|
365
|
-
beforeUpdate: []
|
|
366
|
-
}
|
|
367
|
-
);
|
|
368
|
-
|
|
369
|
-
const loadRoute = [
|
|
370
|
-
async () => {
|
|
371
|
-
return Promise.all(
|
|
372
|
-
to.matched.reduce<Array<Promise<any>>>((acc, route) => {
|
|
373
|
-
if (!route.component && route.asyncComponent) {
|
|
374
|
-
acc.push(
|
|
375
|
-
new Promise<void>((resolve, reject) => {
|
|
376
|
-
if (!route.component && route.asyncComponent) {
|
|
377
|
-
route.asyncComponent().then((resolved) => {
|
|
378
|
-
if (!resolved) {
|
|
379
|
-
reject(
|
|
380
|
-
new Error(
|
|
381
|
-
`Couldn't resolve component at "${route.path}". Ensure you passed a function that returns a promise.`
|
|
382
|
-
)
|
|
383
|
-
);
|
|
384
|
-
}
|
|
385
|
-
route.component = isESModule(resolved)
|
|
386
|
-
? resolved.default
|
|
387
|
-
: resolved;
|
|
388
|
-
resolve();
|
|
389
|
-
});
|
|
390
|
-
}
|
|
391
|
-
})
|
|
392
|
-
);
|
|
393
|
-
}
|
|
394
|
-
return acc;
|
|
395
|
-
}, [])
|
|
396
|
-
);
|
|
397
|
-
}
|
|
398
|
-
];
|
|
399
|
-
|
|
400
|
-
return {
|
|
401
|
-
beforeEach,
|
|
402
|
-
afterEach,
|
|
403
|
-
beforeEnter,
|
|
404
|
-
beforeUpdate,
|
|
405
|
-
beforeLeave,
|
|
406
|
-
loadRoute
|
|
407
|
-
};
|
|
408
|
-
}
|
package/src/history/html.ts
DELETED
|
@@ -1,228 +0,0 @@
|
|
|
1
|
-
import type { RouterInstance, RouterRawLocation } from '../types';
|
|
2
|
-
import {
|
|
3
|
-
computeScrollPosition,
|
|
4
|
-
getKeepScrollPosition,
|
|
5
|
-
getSavedScrollPosition,
|
|
6
|
-
isPathWithProtocolOrDomain,
|
|
7
|
-
normalizeLocation,
|
|
8
|
-
openWindow,
|
|
9
|
-
saveScrollPosition,
|
|
10
|
-
scrollToPosition
|
|
11
|
-
} from '../utils';
|
|
12
|
-
import { BaseRouterHistory } from './base';
|
|
13
|
-
|
|
14
|
-
export class HtmlHistory extends BaseRouterHistory {
|
|
15
|
-
constructor(router: RouterInstance) {
|
|
16
|
-
super(router);
|
|
17
|
-
|
|
18
|
-
if ('scrollRestoration' in window.history) {
|
|
19
|
-
// 只有在 html 模式下才需要修改历史滚动模式
|
|
20
|
-
window.history.scrollRestoration = 'manual';
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
// 获取当前地址,包括 path query hash
|
|
25
|
-
getCurrentLocation() {
|
|
26
|
-
const { href } = window.location;
|
|
27
|
-
const { state } = window.history;
|
|
28
|
-
const { path, base, ...rest } = normalizeLocation(
|
|
29
|
-
href,
|
|
30
|
-
this.router.base
|
|
31
|
-
);
|
|
32
|
-
return {
|
|
33
|
-
path: path.replace(new RegExp(`^(${base})`), ''),
|
|
34
|
-
base,
|
|
35
|
-
...rest,
|
|
36
|
-
state
|
|
37
|
-
};
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
onPopState = (e: PopStateEvent) => {
|
|
41
|
-
if (this.isFrozen) return;
|
|
42
|
-
if (this.router.checkLayerState(e.state)) return;
|
|
43
|
-
|
|
44
|
-
const current = Object.assign({}, this.current);
|
|
45
|
-
|
|
46
|
-
// 当路由变化时触发跳转事件
|
|
47
|
-
this.transitionTo(this.getCurrentLocation(), async (route) => {
|
|
48
|
-
const { state } = window.history;
|
|
49
|
-
saveScrollPosition(current.fullPath, computeScrollPosition());
|
|
50
|
-
setTimeout(async () => {
|
|
51
|
-
const keepScrollPosition = state.keepScrollPosition;
|
|
52
|
-
if (keepScrollPosition) {
|
|
53
|
-
return;
|
|
54
|
-
}
|
|
55
|
-
const savedPosition = getSavedScrollPosition(route.fullPath);
|
|
56
|
-
const position = await this.router.scrollBehavior(
|
|
57
|
-
current,
|
|
58
|
-
route,
|
|
59
|
-
savedPosition
|
|
60
|
-
);
|
|
61
|
-
|
|
62
|
-
const { nextTick } = this.router.options;
|
|
63
|
-
if (position) {
|
|
64
|
-
nextTick && (await nextTick());
|
|
65
|
-
scrollToPosition(position);
|
|
66
|
-
}
|
|
67
|
-
});
|
|
68
|
-
});
|
|
69
|
-
};
|
|
70
|
-
|
|
71
|
-
async init({ replace }: { replace?: boolean } = { replace: true }) {
|
|
72
|
-
const { initUrl } = this.router.options;
|
|
73
|
-
let route = this.getCurrentLocation();
|
|
74
|
-
if (initUrl !== undefined) {
|
|
75
|
-
// 存在 initUrl 则用 initUrl 进行初始化
|
|
76
|
-
route = this.resolve(initUrl) as any;
|
|
77
|
-
} else {
|
|
78
|
-
const state = history.state || {};
|
|
79
|
-
route.state = {
|
|
80
|
-
...state,
|
|
81
|
-
_ancientRoute: state._ancientRoute ?? true // 最古历史的标记, 在调用返回事件时如果有这个标记则直接调用没有历史记录的钩子
|
|
82
|
-
};
|
|
83
|
-
}
|
|
84
|
-
if (replace) {
|
|
85
|
-
await this.replace(route as RouterRawLocation);
|
|
86
|
-
} else {
|
|
87
|
-
await this.push(route as RouterRawLocation);
|
|
88
|
-
}
|
|
89
|
-
this.setupListeners();
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
// 设置监听函数
|
|
93
|
-
setupListeners() {
|
|
94
|
-
window.addEventListener('popstate', this.onPopState);
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
destroy() {
|
|
98
|
-
window.removeEventListener('popstate', this.onPopState);
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
pushWindow(location: RouterRawLocation) {
|
|
102
|
-
if (this.isFrozen) return;
|
|
103
|
-
this.handleOutside(location, false, true);
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
replaceWindow(location: RouterRawLocation) {
|
|
107
|
-
if (this.isFrozen) return;
|
|
108
|
-
this.handleOutside(location, true, true);
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
// 处理外站跳转逻辑
|
|
112
|
-
handleOutside(
|
|
113
|
-
location: RouterRawLocation,
|
|
114
|
-
replace = false,
|
|
115
|
-
// 是否是 pushWindow/replaceWindow 触发的
|
|
116
|
-
isTriggerWithWindow = false
|
|
117
|
-
) {
|
|
118
|
-
const base = this.router.base;
|
|
119
|
-
const { flag, route } = isPathWithProtocolOrDomain(location, base);
|
|
120
|
-
const router = this.router;
|
|
121
|
-
const { handleOutside, validateOutside } = router.options;
|
|
122
|
-
|
|
123
|
-
// 不以域名开头 或 域名相同 都认为是同域
|
|
124
|
-
const isSameHost = !flag || window.location.hostname === route.hostname;
|
|
125
|
-
|
|
126
|
-
// 如果 不是 pushWindow/replaceWindow 触发的
|
|
127
|
-
if (!isTriggerWithWindow) {
|
|
128
|
-
// 如果域名相同 和 非外站(存在就算同域也会被视为外站的情况) 则跳出
|
|
129
|
-
if (isSameHost && !validateOutside?.({ router, location, route })) {
|
|
130
|
-
return false;
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
// 如果有配置跳转外站函数,则执行配置函数
|
|
135
|
-
// 如果配置函数返回 true 则认为其处理了打开逻辑,跳出
|
|
136
|
-
const res = handleOutside?.({
|
|
137
|
-
router,
|
|
138
|
-
route,
|
|
139
|
-
replace,
|
|
140
|
-
isTriggerWithWindow,
|
|
141
|
-
isSameHost
|
|
142
|
-
});
|
|
143
|
-
if (res === false) {
|
|
144
|
-
// 如果配置函数返回 false 则跳出
|
|
145
|
-
return true;
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
if (replace) {
|
|
149
|
-
window.location.replace(route.href);
|
|
150
|
-
} else {
|
|
151
|
-
const { hostname, href } = route;
|
|
152
|
-
openWindow(href, hostname);
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
return true;
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
// 新增路由记录跳转
|
|
159
|
-
async push(location: RouterRawLocation) {
|
|
160
|
-
await this.jump(location, false);
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
// 替换当前路由记录跳转
|
|
164
|
-
async replace(location: RouterRawLocation) {
|
|
165
|
-
await this.jump(location, true);
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
// 跳转方法
|
|
169
|
-
async jump(location: RouterRawLocation, replace = false) {
|
|
170
|
-
if (this.isFrozen) return;
|
|
171
|
-
if (this.handleOutside(location, replace)) {
|
|
172
|
-
return;
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
const current = Object.assign({}, this.current);
|
|
176
|
-
await this.transitionTo(location, (route) => {
|
|
177
|
-
const keepScrollPosition = getKeepScrollPosition(location);
|
|
178
|
-
if (!keepScrollPosition) {
|
|
179
|
-
saveScrollPosition(current.fullPath, computeScrollPosition());
|
|
180
|
-
scrollToPosition({ left: 0, top: 0 });
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
const state = Object.assign(
|
|
184
|
-
replace
|
|
185
|
-
? { ...history.state, ...route.state }
|
|
186
|
-
: { ...route.state, _ancientRoute: false },
|
|
187
|
-
{ keepScrollPosition }
|
|
188
|
-
);
|
|
189
|
-
window.history[replace ? 'replaceState' : 'pushState'](
|
|
190
|
-
state,
|
|
191
|
-
'',
|
|
192
|
-
route.fullPath
|
|
193
|
-
);
|
|
194
|
-
|
|
195
|
-
this.router.updateLayerState(route);
|
|
196
|
-
});
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
go(delta: number): void {
|
|
200
|
-
if (this.isFrozen) return;
|
|
201
|
-
window.history.go(delta);
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
forward(): void {
|
|
205
|
-
if (this.isFrozen) return;
|
|
206
|
-
window.history.forward();
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
protected timer: NodeJS.Timeout | null = null;
|
|
210
|
-
|
|
211
|
-
back(): void {
|
|
212
|
-
if (this.isFrozen) return;
|
|
213
|
-
const oldState = history.state;
|
|
214
|
-
const noBackNavigation = this.router.options.noBackNavigation;
|
|
215
|
-
if (oldState._ancientRoute === true) {
|
|
216
|
-
noBackNavigation && noBackNavigation(this.router);
|
|
217
|
-
return;
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
window.history.back();
|
|
221
|
-
this.timer = setTimeout(() => {
|
|
222
|
-
if (history.state === oldState) {
|
|
223
|
-
noBackNavigation && noBackNavigation(this.router);
|
|
224
|
-
}
|
|
225
|
-
this.timer = null;
|
|
226
|
-
}, 80);
|
|
227
|
-
}
|
|
228
|
-
}
|
package/src/history/index.ts
DELETED
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
import { type RouterInstance, RouterMode } from '../types';
|
|
2
|
-
import { AbstractHistory } from './abstract';
|
|
3
|
-
import { HtmlHistory } from './html';
|
|
4
|
-
|
|
5
|
-
export function createHistory({
|
|
6
|
-
router,
|
|
7
|
-
mode
|
|
8
|
-
}: {
|
|
9
|
-
router: RouterInstance;
|
|
10
|
-
mode: RouterMode;
|
|
11
|
-
}) {
|
|
12
|
-
switch (mode) {
|
|
13
|
-
case RouterMode.HISTORY:
|
|
14
|
-
return new HtmlHistory(router);
|
|
15
|
-
case RouterMode.ABSTRACT:
|
|
16
|
-
return new AbstractHistory(router);
|
|
17
|
-
default:
|
|
18
|
-
throw new Error('not support mode');
|
|
19
|
-
}
|
|
20
|
-
}
|