@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.
Files changed (155) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +70 -0
  3. package/README.zh-CN.md +70 -0
  4. package/dist/error.d.ts +23 -0
  5. package/dist/error.mjs +61 -0
  6. package/dist/increment-id.d.ts +7 -0
  7. package/dist/increment-id.mjs +11 -0
  8. package/dist/index.d.ts +5 -3
  9. package/dist/index.mjs +14 -3
  10. package/dist/index.test.mjs +8 -0
  11. package/dist/location.d.ts +15 -0
  12. package/dist/location.mjs +53 -0
  13. package/dist/location.test.d.ts +8 -0
  14. package/dist/location.test.mjs +370 -0
  15. package/dist/matcher.d.ts +3 -0
  16. package/dist/matcher.mjs +44 -0
  17. package/dist/matcher.test.mjs +1492 -0
  18. package/dist/micro-app.d.ts +18 -0
  19. package/dist/micro-app.dom.test.d.ts +1 -0
  20. package/dist/micro-app.dom.test.mjs +532 -0
  21. package/dist/micro-app.mjs +80 -0
  22. package/dist/navigation.d.ts +43 -0
  23. package/dist/navigation.mjs +143 -0
  24. package/dist/navigation.test.d.ts +1 -0
  25. package/dist/navigation.test.mjs +681 -0
  26. package/dist/options.d.ts +4 -0
  27. package/dist/options.mjs +88 -0
  28. package/dist/route-task.d.ts +40 -0
  29. package/dist/route-task.mjs +75 -0
  30. package/dist/route-task.test.d.ts +1 -0
  31. package/dist/route-task.test.mjs +673 -0
  32. package/dist/route-transition.d.ts +53 -0
  33. package/dist/route-transition.mjs +307 -0
  34. package/dist/route-transition.test.d.ts +1 -0
  35. package/dist/route-transition.test.mjs +146 -0
  36. package/dist/route.d.ts +72 -0
  37. package/dist/route.mjs +194 -0
  38. package/dist/route.test.d.ts +1 -0
  39. package/dist/route.test.mjs +1664 -0
  40. package/dist/router-back.test.d.ts +1 -0
  41. package/dist/router-back.test.mjs +361 -0
  42. package/dist/router-forward.test.d.ts +1 -0
  43. package/dist/router-forward.test.mjs +376 -0
  44. package/dist/router-go.test.d.ts +1 -0
  45. package/dist/router-go.test.mjs +73 -0
  46. package/dist/router-guards-cleanup.test.d.ts +1 -0
  47. package/dist/router-guards-cleanup.test.mjs +437 -0
  48. package/dist/router-link.d.ts +10 -0
  49. package/dist/router-link.mjs +126 -0
  50. package/dist/router-push.test.d.ts +1 -0
  51. package/dist/router-push.test.mjs +115 -0
  52. package/dist/router-replace.test.d.ts +1 -0
  53. package/dist/router-replace.test.mjs +114 -0
  54. package/dist/router-resolve.test.d.ts +1 -0
  55. package/dist/router-resolve.test.mjs +393 -0
  56. package/dist/router-restart-app.dom.test.d.ts +1 -0
  57. package/dist/router-restart-app.dom.test.mjs +616 -0
  58. package/dist/router-window-navigation.test.d.ts +1 -0
  59. package/dist/router-window-navigation.test.mjs +359 -0
  60. package/dist/router.d.ts +109 -102
  61. package/dist/router.mjs +260 -361
  62. package/dist/types.d.ts +246 -0
  63. package/dist/types.mjs +18 -0
  64. package/dist/util.d.ts +26 -0
  65. package/dist/util.mjs +53 -0
  66. package/dist/util.test.d.ts +1 -0
  67. package/dist/util.test.mjs +1020 -0
  68. package/package.json +10 -13
  69. package/src/error.ts +84 -0
  70. package/src/increment-id.ts +12 -0
  71. package/src/index.test.ts +9 -0
  72. package/src/index.ts +54 -3
  73. package/src/location.test.ts +406 -0
  74. package/src/location.ts +96 -0
  75. package/src/matcher.test.ts +1685 -0
  76. package/src/matcher.ts +59 -0
  77. package/src/micro-app.dom.test.ts +708 -0
  78. package/src/micro-app.ts +101 -0
  79. package/src/navigation.test.ts +858 -0
  80. package/src/navigation.ts +195 -0
  81. package/src/options.ts +131 -0
  82. package/src/route-task.test.ts +901 -0
  83. package/src/route-task.ts +105 -0
  84. package/src/route-transition.test.ts +178 -0
  85. package/src/route-transition.ts +425 -0
  86. package/src/route.test.ts +2014 -0
  87. package/src/route.ts +308 -0
  88. package/src/router-back.test.ts +487 -0
  89. package/src/router-forward.test.ts +506 -0
  90. package/src/router-go.test.ts +91 -0
  91. package/src/router-guards-cleanup.test.ts +595 -0
  92. package/src/router-link.ts +235 -0
  93. package/src/router-push.test.ts +140 -0
  94. package/src/router-replace.test.ts +139 -0
  95. package/src/router-resolve.test.ts +475 -0
  96. package/src/router-restart-app.dom.test.ts +783 -0
  97. package/src/router-window-navigation.test.ts +457 -0
  98. package/src/router.ts +289 -470
  99. package/src/types.ts +341 -0
  100. package/src/util.test.ts +1262 -0
  101. package/src/util.ts +116 -0
  102. package/dist/history/abstract.d.ts +0 -29
  103. package/dist/history/abstract.mjs +0 -107
  104. package/dist/history/base.d.ts +0 -79
  105. package/dist/history/base.mjs +0 -275
  106. package/dist/history/html.d.ts +0 -22
  107. package/dist/history/html.mjs +0 -183
  108. package/dist/history/index.d.ts +0 -7
  109. package/dist/history/index.mjs +0 -16
  110. package/dist/matcher/create-matcher.d.ts +0 -5
  111. package/dist/matcher/create-matcher.mjs +0 -218
  112. package/dist/matcher/create-matcher.spec.mjs +0 -0
  113. package/dist/matcher/index.d.ts +0 -1
  114. package/dist/matcher/index.mjs +0 -1
  115. package/dist/task-pipe/index.d.ts +0 -1
  116. package/dist/task-pipe/index.mjs +0 -1
  117. package/dist/task-pipe/task.d.ts +0 -30
  118. package/dist/task-pipe/task.mjs +0 -66
  119. package/dist/utils/bom.d.ts +0 -5
  120. package/dist/utils/bom.mjs +0 -10
  121. package/dist/utils/encoding.d.ts +0 -48
  122. package/dist/utils/encoding.mjs +0 -44
  123. package/dist/utils/guards.d.ts +0 -9
  124. package/dist/utils/guards.mjs +0 -12
  125. package/dist/utils/index.d.ts +0 -7
  126. package/dist/utils/index.mjs +0 -27
  127. package/dist/utils/path.d.ts +0 -60
  128. package/dist/utils/path.mjs +0 -281
  129. package/dist/utils/path.spec.mjs +0 -27
  130. package/dist/utils/scroll.d.ts +0 -25
  131. package/dist/utils/scroll.mjs +0 -59
  132. package/dist/utils/utils.d.ts +0 -16
  133. package/dist/utils/utils.mjs +0 -11
  134. package/dist/utils/warn.d.ts +0 -2
  135. package/dist/utils/warn.mjs +0 -12
  136. package/src/history/abstract.ts +0 -149
  137. package/src/history/base.ts +0 -408
  138. package/src/history/html.ts +0 -228
  139. package/src/history/index.ts +0 -20
  140. package/src/matcher/create-matcher.spec.ts +0 -3
  141. package/src/matcher/create-matcher.ts +0 -293
  142. package/src/matcher/index.ts +0 -1
  143. package/src/task-pipe/index.ts +0 -1
  144. package/src/task-pipe/task.ts +0 -97
  145. package/src/utils/bom.ts +0 -14
  146. package/src/utils/encoding.ts +0 -153
  147. package/src/utils/guards.ts +0 -25
  148. package/src/utils/index.ts +0 -27
  149. package/src/utils/path.spec.ts +0 -32
  150. package/src/utils/path.ts +0 -417
  151. package/src/utils/scroll.ts +0 -120
  152. package/src/utils/utils.ts +0 -30
  153. package/src/utils/warn.ts +0 -13
  154. /package/dist/{matcher/create-matcher.spec.d.ts → index.test.d.ts} +0 -0
  155. /package/dist/{utils/path.spec.d.ts → matcher.test.d.ts} +0 -0
@@ -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
- }
@@ -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
- }
@@ -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
- }
@@ -1,3 +0,0 @@
1
- import { describe, it } from 'vitest';
2
-
3
- import { createRouterMatcher } from './create-matcher';