@esmx/router 3.0.0-rc.18 → 3.0.0-rc.20
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/util.ts
ADDED
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import type { Route, RouteConfirmHookResult, RouteMatchType } from './types';
|
|
2
|
+
export const isBrowser = typeof window === 'object';
|
|
3
|
+
|
|
4
|
+
export function isNotNullish(value: unknown): boolean {
|
|
5
|
+
return (
|
|
6
|
+
value !== undefined &&
|
|
7
|
+
value !== null &&
|
|
8
|
+
!Number.isNaN(
|
|
9
|
+
value instanceof Number
|
|
10
|
+
? value.valueOf() // For new Number() cases
|
|
11
|
+
: value
|
|
12
|
+
)
|
|
13
|
+
);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export function isPlainObject(o: unknown): o is Record<string, any> {
|
|
17
|
+
return (
|
|
18
|
+
o?.constructor === Object ||
|
|
19
|
+
Object.prototype.toString.call(o) === '[object Object]'
|
|
20
|
+
);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Check if value is a valid non-empty plain object
|
|
25
|
+
* Only check enumerable string keys to ensure it's a proper plain object
|
|
26
|
+
* @param value Value to check
|
|
27
|
+
* @returns true if it's a valid non-empty plain object
|
|
28
|
+
*/
|
|
29
|
+
export function isNonEmptyPlainObject(
|
|
30
|
+
value: unknown
|
|
31
|
+
): value is Record<string, any> {
|
|
32
|
+
if (!isPlainObject(value)) {
|
|
33
|
+
return false;
|
|
34
|
+
}
|
|
35
|
+
// Only check enumerable string keys to ensure valid properties of plain object
|
|
36
|
+
return Object.keys(value as Record<string, any>).length > 0;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export const removeFromArray = <T>(arr: T[], ele: T) => {
|
|
40
|
+
if (!Array.isArray(arr) || arr.length === 0) return;
|
|
41
|
+
const i = Number.isNaN(ele)
|
|
42
|
+
? // If ele is NaN, use findIndex to search for NaN, because NaN !== NaN, so we can't use indexOf directly
|
|
43
|
+
arr.findIndex((item) => Number.isNaN(item))
|
|
44
|
+
: arr.indexOf(ele);
|
|
45
|
+
if (i === -1) return;
|
|
46
|
+
arr.splice(i, 1);
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
export function isValidConfirmHookResult(
|
|
50
|
+
result: unknown
|
|
51
|
+
): result is Exclude<RouteConfirmHookResult, void> {
|
|
52
|
+
return (
|
|
53
|
+
result === false ||
|
|
54
|
+
typeof result === 'function' ||
|
|
55
|
+
typeof result === 'string' ||
|
|
56
|
+
isPlainObject(result)
|
|
57
|
+
);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export function isUrlEqual(url1: URL, url2?: URL | null): boolean {
|
|
61
|
+
// If url2 doesn't exist, return false
|
|
62
|
+
if (!url2) {
|
|
63
|
+
return false;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// If it's the same object reference, return true directly
|
|
67
|
+
if (url1 === url2) {
|
|
68
|
+
return true;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// Copy and sort query parameters
|
|
72
|
+
(url1 = new URL(url1)).searchParams.sort();
|
|
73
|
+
(url2 = new URL(url2)).searchParams.sort();
|
|
74
|
+
// Avoid trailing hash symbol impact from empty hash
|
|
75
|
+
// biome-ignore lint/correctness/noSelfAssign:
|
|
76
|
+
url1.hash = url1.hash;
|
|
77
|
+
// biome-ignore lint/correctness/noSelfAssign:
|
|
78
|
+
url2.hash = url2.hash;
|
|
79
|
+
return url1.href === url2.href;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Compare if two routes match
|
|
84
|
+
*
|
|
85
|
+
* @param route1 First route object
|
|
86
|
+
* @param route2 Second route object, may be null
|
|
87
|
+
* @param matchType Match type
|
|
88
|
+
* - 'route': Route-level matching, compare if route configurations are the same
|
|
89
|
+
* - 'exact': Exact matching, compare if full paths are the same
|
|
90
|
+
* - 'include': Include matching, check if route1 path starts with route2 path
|
|
91
|
+
* @returns Whether they match
|
|
92
|
+
*/
|
|
93
|
+
export function isRouteMatched(
|
|
94
|
+
route1: Route,
|
|
95
|
+
route2: Route | null,
|
|
96
|
+
matchType: RouteMatchType
|
|
97
|
+
): boolean {
|
|
98
|
+
if (!route2) return false;
|
|
99
|
+
|
|
100
|
+
switch (matchType) {
|
|
101
|
+
case 'route':
|
|
102
|
+
// Route-level matching - compare route configurations
|
|
103
|
+
return route1.config === route2.config;
|
|
104
|
+
|
|
105
|
+
case 'exact':
|
|
106
|
+
// Exact matching - full paths are identical
|
|
107
|
+
return route1.fullPath === route2.fullPath;
|
|
108
|
+
|
|
109
|
+
case 'include':
|
|
110
|
+
// Include matching - route1 path contains route2 path
|
|
111
|
+
return route1.fullPath.startsWith(route2.fullPath);
|
|
112
|
+
|
|
113
|
+
default:
|
|
114
|
+
return false;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
import type { Route, RouteRecord, RouterInstance, RouterRawLocation } from '../types';
|
|
2
|
-
import { BaseRouterHistory } from './base';
|
|
3
|
-
export declare class AbstractHistory extends BaseRouterHistory {
|
|
4
|
-
index: number;
|
|
5
|
-
stack: RouteRecord[];
|
|
6
|
-
constructor(router: RouterInstance);
|
|
7
|
-
init({ replace }?: {
|
|
8
|
-
replace?: boolean;
|
|
9
|
-
}): Promise<void>;
|
|
10
|
-
destroy(): void;
|
|
11
|
-
setupListeners(): void;
|
|
12
|
-
isSameHost(location: RouterRawLocation, route: Route): boolean;
|
|
13
|
-
handleOutside(location: RouterRawLocation, replace?: boolean, isTriggerWithWindow?: boolean): boolean;
|
|
14
|
-
push(location: RouterRawLocation): Promise<void>;
|
|
15
|
-
/**
|
|
16
|
-
* 新开浏览器窗口的方法,在服务端会调用 push 作为替代
|
|
17
|
-
*/
|
|
18
|
-
pushWindow(location: RouterRawLocation): Promise<void>;
|
|
19
|
-
replace(location: RouterRawLocation): Promise<void>;
|
|
20
|
-
/**
|
|
21
|
-
* 替换当前浏览器窗口的方法,在服务端会调用 replace 作为替代
|
|
22
|
-
*/
|
|
23
|
-
replaceWindow(location: RouterRawLocation): Promise<void>;
|
|
24
|
-
jump(location: RouterRawLocation, replace?: boolean): Promise<void>;
|
|
25
|
-
_jump(location: RouterRawLocation, replace?: boolean, isTriggerWithWindow?: boolean): Promise<void>;
|
|
26
|
-
go(delta: number): void;
|
|
27
|
-
forward(): void;
|
|
28
|
-
back(): void;
|
|
29
|
-
}
|
|
@@ -1,107 +0,0 @@
|
|
|
1
|
-
import { isPathWithProtocolOrDomain, normalizeLocation } from "../utils/index.mjs";
|
|
2
|
-
import { BaseRouterHistory } from "./base.mjs";
|
|
3
|
-
export class AbstractHistory extends BaseRouterHistory {
|
|
4
|
-
index;
|
|
5
|
-
stack;
|
|
6
|
-
constructor(router) {
|
|
7
|
-
super(router);
|
|
8
|
-
this.index = -1;
|
|
9
|
-
this.stack = [];
|
|
10
|
-
}
|
|
11
|
-
async init({ replace } = { replace: true }) {
|
|
12
|
-
const { initUrl } = this.router.options;
|
|
13
|
-
if (initUrl !== void 0) {
|
|
14
|
-
if (replace) {
|
|
15
|
-
await this.replace(initUrl);
|
|
16
|
-
} else {
|
|
17
|
-
await this.push(initUrl);
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
destroy() {
|
|
22
|
-
}
|
|
23
|
-
// 设置监听函数
|
|
24
|
-
setupListeners() {
|
|
25
|
-
}
|
|
26
|
-
// 服务端判断是否是相同域名
|
|
27
|
-
isSameHost(location, route) {
|
|
28
|
-
const rawLocation = typeof location === "string" ? { path: location } : location;
|
|
29
|
-
if (rawLocation.path === void 0) {
|
|
30
|
-
rawLocation.path = this.current.fullPath;
|
|
31
|
-
}
|
|
32
|
-
const { base } = normalizeLocation(rawLocation, this.router.base);
|
|
33
|
-
return base.includes(route.hostname);
|
|
34
|
-
}
|
|
35
|
-
// 处理外站跳转逻辑
|
|
36
|
-
handleOutside(location, replace = false, isTriggerWithWindow = false) {
|
|
37
|
-
const base = this.router.base;
|
|
38
|
-
const { flag, route } = isPathWithProtocolOrDomain(location, base);
|
|
39
|
-
if (!flag) {
|
|
40
|
-
return false;
|
|
41
|
-
}
|
|
42
|
-
const router = this.router;
|
|
43
|
-
const { validateOutside, handleOutside } = router.options;
|
|
44
|
-
const isSameHost = this.isSameHost(location, route);
|
|
45
|
-
if (isSameHost && !(validateOutside == null ? void 0 : validateOutside({ router, location, route }))) {
|
|
46
|
-
return false;
|
|
47
|
-
}
|
|
48
|
-
handleOutside == null ? void 0 : handleOutside({
|
|
49
|
-
router,
|
|
50
|
-
route,
|
|
51
|
-
replace,
|
|
52
|
-
isTriggerWithWindow,
|
|
53
|
-
isSameHost
|
|
54
|
-
});
|
|
55
|
-
return true;
|
|
56
|
-
}
|
|
57
|
-
// 新增路由记录跳转
|
|
58
|
-
async push(location) {
|
|
59
|
-
await this.jump(location, false);
|
|
60
|
-
}
|
|
61
|
-
/**
|
|
62
|
-
* 新开浏览器窗口的方法,在服务端会调用 push 作为替代
|
|
63
|
-
*/
|
|
64
|
-
async pushWindow(location) {
|
|
65
|
-
await this._jump(location, false, true);
|
|
66
|
-
}
|
|
67
|
-
// 替换当前路由记录跳转
|
|
68
|
-
async replace(location) {
|
|
69
|
-
await this.jump(location, true);
|
|
70
|
-
}
|
|
71
|
-
/**
|
|
72
|
-
* 替换当前浏览器窗口的方法,在服务端会调用 replace 作为替代
|
|
73
|
-
*/
|
|
74
|
-
async replaceWindow(location) {
|
|
75
|
-
await this._jump(location, true, true);
|
|
76
|
-
}
|
|
77
|
-
// 跳转方法
|
|
78
|
-
async jump(location, replace = false) {
|
|
79
|
-
await this._jump(location, replace);
|
|
80
|
-
}
|
|
81
|
-
async _jump(location, replace = false, isTriggerWithWindow = false) {
|
|
82
|
-
if (this.handleOutside(location, replace, isTriggerWithWindow)) {
|
|
83
|
-
return;
|
|
84
|
-
}
|
|
85
|
-
await this.transitionTo(location, (route) => {
|
|
86
|
-
const index = replace ? this.index : this.index + 1;
|
|
87
|
-
this.stack = this.stack.slice(0, index).concat(route);
|
|
88
|
-
});
|
|
89
|
-
}
|
|
90
|
-
go(delta) {
|
|
91
|
-
const targetIndex = this.index + delta;
|
|
92
|
-
if (targetIndex < 0 || targetIndex >= this.stack.length) {
|
|
93
|
-
return;
|
|
94
|
-
}
|
|
95
|
-
const route = this.stack[targetIndex];
|
|
96
|
-
this.index = targetIndex;
|
|
97
|
-
this.updateRoute(route);
|
|
98
|
-
}
|
|
99
|
-
/* 路由历史记录前进方法 */
|
|
100
|
-
forward() {
|
|
101
|
-
this.go(1);
|
|
102
|
-
}
|
|
103
|
-
/* 路由历史记录后退方法 */
|
|
104
|
-
back() {
|
|
105
|
-
this.go(-1);
|
|
106
|
-
}
|
|
107
|
-
}
|
package/dist/history/base.d.ts
DELETED
|
@@ -1,79 +0,0 @@
|
|
|
1
|
-
import { type Tasks } from '../task-pipe';
|
|
2
|
-
import type { RouteRecord, RouterHistory, RouterInstance, RouterRawLocation } from '../types';
|
|
3
|
-
export declare abstract class BaseRouterHistory implements RouterHistory {
|
|
4
|
-
/**
|
|
5
|
-
* 路由类实例
|
|
6
|
-
*/
|
|
7
|
-
router: RouterInstance;
|
|
8
|
-
/**
|
|
9
|
-
* 路由是否冻结
|
|
10
|
-
*/
|
|
11
|
-
get isFrozen(): boolean;
|
|
12
|
-
/**
|
|
13
|
-
* 匹配的当前路由
|
|
14
|
-
*/
|
|
15
|
-
current: RouteRecord;
|
|
16
|
-
constructor(router: RouterInstance);
|
|
17
|
-
/**
|
|
18
|
-
* 更新当前路由
|
|
19
|
-
*/
|
|
20
|
-
updateRoute(route: RouteRecord): void;
|
|
21
|
-
/**
|
|
22
|
-
* 解析路由
|
|
23
|
-
*/
|
|
24
|
-
resolve(location: RouterRawLocation): RouteRecord;
|
|
25
|
-
/**
|
|
26
|
-
* 核心跳转方法
|
|
27
|
-
*/
|
|
28
|
-
transitionTo(location: RouterRawLocation, onComplete?: (route: RouteRecord) => void): Promise<void>;
|
|
29
|
-
/**
|
|
30
|
-
* TODO 逻辑解耦,抽离到task
|
|
31
|
-
* 重定向方法
|
|
32
|
-
*/
|
|
33
|
-
redirectTo(location: RouterRawLocation, from: RouteRecord, onComplete?: (route: RouteRecord) => void): Promise<void>;
|
|
34
|
-
tasks: Tasks | null;
|
|
35
|
-
abortTask(): Promise<void>;
|
|
36
|
-
/**
|
|
37
|
-
* 执行任务
|
|
38
|
-
* 任务分为三部分: 前置守卫(beforeEach、beforeEnter、beforeUpdate、beforeLeave)、加载路由(loadRoute)、后置守卫(afterEach)
|
|
39
|
-
* 根据触发方式不同,执行顺序分别为:
|
|
40
|
-
* 进入路由时: beforeEach -> beforeEnter -> loadRoute -> afterEach
|
|
41
|
-
* 更新路由时: beforeEach -> beforeUpdate -> afterEach
|
|
42
|
-
* 离开路由进入新路由时: beforeLeave -> beforeEach -> beforeEnter -> loadRoute -> afterEach
|
|
43
|
-
* @param from
|
|
44
|
-
* @param to
|
|
45
|
-
*/
|
|
46
|
-
runTask(from: RouteRecord, to: RouteRecord, onComplete?: (route: RouteRecord) => void): Promise<void>;
|
|
47
|
-
/**
|
|
48
|
-
* 新开浏览器窗口的方法,在服务端会调用 push 作为替代
|
|
49
|
-
*/
|
|
50
|
-
abstract pushWindow(location: RouterRawLocation): void;
|
|
51
|
-
/**
|
|
52
|
-
* 替换当前浏览器窗口的方法,在服务端会调用 replace 作为替代
|
|
53
|
-
*/
|
|
54
|
-
abstract replaceWindow(location: RouterRawLocation): void;
|
|
55
|
-
/**
|
|
56
|
-
* 跳转方法,会创建新的历史纪录
|
|
57
|
-
*/
|
|
58
|
-
abstract push(location: RouterRawLocation): Promise<void>;
|
|
59
|
-
/**
|
|
60
|
-
* 跳转方法,替换当前历史记录
|
|
61
|
-
*/
|
|
62
|
-
abstract replace(location: RouterRawLocation): Promise<void>;
|
|
63
|
-
/**
|
|
64
|
-
* 路由移动到指定历史记录方法
|
|
65
|
-
*/
|
|
66
|
-
abstract go(delta: number): void;
|
|
67
|
-
abstract forward(): void;
|
|
68
|
-
abstract back(): void;
|
|
69
|
-
/**
|
|
70
|
-
* 初始化方法
|
|
71
|
-
*/
|
|
72
|
-
abstract init(params?: {
|
|
73
|
-
replace?: boolean;
|
|
74
|
-
}): Promise<void>;
|
|
75
|
-
/**
|
|
76
|
-
* 卸载方法
|
|
77
|
-
*/
|
|
78
|
-
abstract destroy(): void;
|
|
79
|
-
}
|
package/dist/history/base.mjs
DELETED
|
@@ -1,275 +0,0 @@
|
|
|
1
|
-
import { createTasks } from "../task-pipe/index.mjs";
|
|
2
|
-
import {
|
|
3
|
-
isESModule,
|
|
4
|
-
isEqualRoute,
|
|
5
|
-
isSameRoute,
|
|
6
|
-
normalizeLocation,
|
|
7
|
-
stringifyPath
|
|
8
|
-
} from "../utils/index.mjs";
|
|
9
|
-
function createRouteRecord(route = {}) {
|
|
10
|
-
return {
|
|
11
|
-
base: "",
|
|
12
|
-
path: "/",
|
|
13
|
-
fullPath: "/",
|
|
14
|
-
meta: {},
|
|
15
|
-
matched: [],
|
|
16
|
-
query: {},
|
|
17
|
-
queryArray: {},
|
|
18
|
-
params: {},
|
|
19
|
-
hash: "",
|
|
20
|
-
state: {},
|
|
21
|
-
...route
|
|
22
|
-
};
|
|
23
|
-
}
|
|
24
|
-
export class BaseRouterHistory {
|
|
25
|
-
/**
|
|
26
|
-
* 路由类实例
|
|
27
|
-
*/
|
|
28
|
-
router;
|
|
29
|
-
/**
|
|
30
|
-
* 路由是否冻结
|
|
31
|
-
*/
|
|
32
|
-
get isFrozen() {
|
|
33
|
-
return this.router.isFrozen;
|
|
34
|
-
}
|
|
35
|
-
/**
|
|
36
|
-
* 匹配的当前路由
|
|
37
|
-
*/
|
|
38
|
-
current = createRouteRecord();
|
|
39
|
-
constructor(router) {
|
|
40
|
-
this.router = router;
|
|
41
|
-
Object.defineProperty(this, "router", {
|
|
42
|
-
enumerable: false
|
|
43
|
-
});
|
|
44
|
-
}
|
|
45
|
-
/**
|
|
46
|
-
* 更新当前路由
|
|
47
|
-
*/
|
|
48
|
-
updateRoute(route) {
|
|
49
|
-
this.current = route;
|
|
50
|
-
this.router.updateRoute(route);
|
|
51
|
-
}
|
|
52
|
-
/**
|
|
53
|
-
* 解析路由
|
|
54
|
-
*/
|
|
55
|
-
resolve(location) {
|
|
56
|
-
const rawLocation = typeof location === "string" ? { path: location } : location;
|
|
57
|
-
if (rawLocation.path === void 0) {
|
|
58
|
-
rawLocation.path = this.current.fullPath;
|
|
59
|
-
}
|
|
60
|
-
const { base, ...normalizedLocation } = normalizeLocation(
|
|
61
|
-
rawLocation,
|
|
62
|
-
this.router.base
|
|
63
|
-
);
|
|
64
|
-
const matcher = this.router.matcher.match(normalizedLocation, { base });
|
|
65
|
-
if (matcher) {
|
|
66
|
-
return matcher;
|
|
67
|
-
}
|
|
68
|
-
const {
|
|
69
|
-
path = "",
|
|
70
|
-
params = {},
|
|
71
|
-
query = {},
|
|
72
|
-
queryArray = {},
|
|
73
|
-
hash = "",
|
|
74
|
-
state = {}
|
|
75
|
-
} = normalizedLocation;
|
|
76
|
-
const route = createRouteRecord({
|
|
77
|
-
base,
|
|
78
|
-
fullPath: stringifyPath({
|
|
79
|
-
pathname: path,
|
|
80
|
-
query,
|
|
81
|
-
queryArray,
|
|
82
|
-
hash
|
|
83
|
-
}),
|
|
84
|
-
path,
|
|
85
|
-
params,
|
|
86
|
-
query,
|
|
87
|
-
queryArray,
|
|
88
|
-
hash,
|
|
89
|
-
state
|
|
90
|
-
});
|
|
91
|
-
return route;
|
|
92
|
-
}
|
|
93
|
-
/**
|
|
94
|
-
* 核心跳转方法
|
|
95
|
-
*/
|
|
96
|
-
async transitionTo(location, onComplete) {
|
|
97
|
-
if (this.isFrozen) return;
|
|
98
|
-
const route = this.resolve(location);
|
|
99
|
-
this.abortTask();
|
|
100
|
-
if (isEqualRoute(this.current, route)) {
|
|
101
|
-
return;
|
|
102
|
-
}
|
|
103
|
-
await this.runTask(this.current, route, onComplete);
|
|
104
|
-
}
|
|
105
|
-
/**
|
|
106
|
-
* TODO 逻辑解耦,抽离到task
|
|
107
|
-
* 重定向方法
|
|
108
|
-
*/
|
|
109
|
-
async redirectTo(location, from, onComplete) {
|
|
110
|
-
const route = this.resolve(location);
|
|
111
|
-
this.abortTask();
|
|
112
|
-
if (isEqualRoute(this.current, route)) {
|
|
113
|
-
return;
|
|
114
|
-
}
|
|
115
|
-
await this.runTask(
|
|
116
|
-
this.current,
|
|
117
|
-
{
|
|
118
|
-
...route,
|
|
119
|
-
redirectedFrom: from
|
|
120
|
-
},
|
|
121
|
-
onComplete
|
|
122
|
-
);
|
|
123
|
-
}
|
|
124
|
-
/* 当前执行的任务 */
|
|
125
|
-
tasks = null;
|
|
126
|
-
/* 取消任务 */
|
|
127
|
-
async abortTask() {
|
|
128
|
-
var _a;
|
|
129
|
-
(_a = this.tasks) == null ? void 0 : _a.abort();
|
|
130
|
-
}
|
|
131
|
-
/**
|
|
132
|
-
* 执行任务
|
|
133
|
-
* 任务分为三部分: 前置守卫(beforeEach、beforeEnter、beforeUpdate、beforeLeave)、加载路由(loadRoute)、后置守卫(afterEach)
|
|
134
|
-
* 根据触发方式不同,执行顺序分别为:
|
|
135
|
-
* 进入路由时: beforeEach -> beforeEnter -> loadRoute -> afterEach
|
|
136
|
-
* 更新路由时: beforeEach -> beforeUpdate -> afterEach
|
|
137
|
-
* 离开路由进入新路由时: beforeLeave -> beforeEach -> beforeEnter -> loadRoute -> afterEach
|
|
138
|
-
* @param from
|
|
139
|
-
* @param to
|
|
140
|
-
*/
|
|
141
|
-
async runTask(from, to, onComplete) {
|
|
142
|
-
var _a;
|
|
143
|
-
const {
|
|
144
|
-
beforeEach,
|
|
145
|
-
beforeEnter,
|
|
146
|
-
beforeUpdate,
|
|
147
|
-
beforeLeave,
|
|
148
|
-
afterEach,
|
|
149
|
-
loadRoute
|
|
150
|
-
} = getNavigationHooks(this.router, from, to);
|
|
151
|
-
const guardBeforeTasks = createTasks();
|
|
152
|
-
const guardAfterTasks = createTasks();
|
|
153
|
-
const loadRouteTasks = createTasks();
|
|
154
|
-
if (isSameRoute(from, to)) {
|
|
155
|
-
guardBeforeTasks.add([...beforeEach, ...beforeUpdate]);
|
|
156
|
-
guardAfterTasks.add(afterEach);
|
|
157
|
-
} else {
|
|
158
|
-
guardBeforeTasks.add([
|
|
159
|
-
...beforeLeave,
|
|
160
|
-
...beforeEach,
|
|
161
|
-
...beforeEnter
|
|
162
|
-
]);
|
|
163
|
-
loadRouteTasks.add(loadRoute);
|
|
164
|
-
guardAfterTasks.add(afterEach);
|
|
165
|
-
}
|
|
166
|
-
this.tasks = guardBeforeTasks;
|
|
167
|
-
await guardBeforeTasks.run({
|
|
168
|
-
cb: async (res) => {
|
|
169
|
-
var _a2;
|
|
170
|
-
switch (typeof res) {
|
|
171
|
-
case "boolean":
|
|
172
|
-
if (!res) {
|
|
173
|
-
(_a2 = this.tasks) == null ? void 0 : _a2.abort();
|
|
174
|
-
}
|
|
175
|
-
break;
|
|
176
|
-
case "undefined":
|
|
177
|
-
break;
|
|
178
|
-
default:
|
|
179
|
-
await this.redirectTo(res, from, onComplete);
|
|
180
|
-
break;
|
|
181
|
-
}
|
|
182
|
-
},
|
|
183
|
-
final: async () => {
|
|
184
|
-
this.tasks = loadRouteTasks;
|
|
185
|
-
await loadRouteTasks.run();
|
|
186
|
-
}
|
|
187
|
-
});
|
|
188
|
-
if (((_a = this.tasks) == null ? void 0 : _a.status) === "finished") {
|
|
189
|
-
this.tasks = null;
|
|
190
|
-
guardAfterTasks.run();
|
|
191
|
-
onComplete && onComplete(to);
|
|
192
|
-
this.updateRoute(to);
|
|
193
|
-
}
|
|
194
|
-
}
|
|
195
|
-
}
|
|
196
|
-
function getNavigationHooks(router, from, to) {
|
|
197
|
-
const beforeEach = router.guards.beforeEach.map((guard) => {
|
|
198
|
-
return () => {
|
|
199
|
-
return guard(from, to);
|
|
200
|
-
};
|
|
201
|
-
});
|
|
202
|
-
const afterEach = router.guards.afterEach.map((guard) => {
|
|
203
|
-
return () => {
|
|
204
|
-
return guard(from, to);
|
|
205
|
-
};
|
|
206
|
-
});
|
|
207
|
-
const { beforeLeave } = from.matched.reduce(
|
|
208
|
-
(acc, { beforeLeave: beforeLeave2 }) => {
|
|
209
|
-
if (beforeLeave2) {
|
|
210
|
-
acc.beforeLeave.unshift(() => {
|
|
211
|
-
return beforeLeave2(from, to);
|
|
212
|
-
});
|
|
213
|
-
}
|
|
214
|
-
return acc;
|
|
215
|
-
},
|
|
216
|
-
{
|
|
217
|
-
beforeLeave: []
|
|
218
|
-
}
|
|
219
|
-
);
|
|
220
|
-
const { beforeEnter, beforeUpdate } = to.matched.reduce(
|
|
221
|
-
(acc, { beforeEnter: beforeEnter2, beforeUpdate: beforeUpdate2 }) => {
|
|
222
|
-
if (beforeEnter2) {
|
|
223
|
-
acc.beforeEnter.push(() => {
|
|
224
|
-
return beforeEnter2(from, to);
|
|
225
|
-
});
|
|
226
|
-
}
|
|
227
|
-
if (beforeUpdate2) {
|
|
228
|
-
acc.beforeUpdate.push(() => {
|
|
229
|
-
return beforeUpdate2(from, to);
|
|
230
|
-
});
|
|
231
|
-
}
|
|
232
|
-
return acc;
|
|
233
|
-
},
|
|
234
|
-
{
|
|
235
|
-
beforeEnter: [],
|
|
236
|
-
beforeUpdate: []
|
|
237
|
-
}
|
|
238
|
-
);
|
|
239
|
-
const loadRoute = [
|
|
240
|
-
async () => {
|
|
241
|
-
return Promise.all(
|
|
242
|
-
to.matched.reduce((acc, route) => {
|
|
243
|
-
if (!route.component && route.asyncComponent) {
|
|
244
|
-
acc.push(
|
|
245
|
-
new Promise((resolve, reject) => {
|
|
246
|
-
if (!route.component && route.asyncComponent) {
|
|
247
|
-
route.asyncComponent().then((resolved) => {
|
|
248
|
-
if (!resolved) {
|
|
249
|
-
reject(
|
|
250
|
-
new Error(
|
|
251
|
-
`Couldn't resolve component at "${route.path}". Ensure you passed a function that returns a promise.`
|
|
252
|
-
)
|
|
253
|
-
);
|
|
254
|
-
}
|
|
255
|
-
route.component = isESModule(resolved) ? resolved.default : resolved;
|
|
256
|
-
resolve();
|
|
257
|
-
});
|
|
258
|
-
}
|
|
259
|
-
})
|
|
260
|
-
);
|
|
261
|
-
}
|
|
262
|
-
return acc;
|
|
263
|
-
}, [])
|
|
264
|
-
);
|
|
265
|
-
}
|
|
266
|
-
];
|
|
267
|
-
return {
|
|
268
|
-
beforeEach,
|
|
269
|
-
afterEach,
|
|
270
|
-
beforeEnter,
|
|
271
|
-
beforeUpdate,
|
|
272
|
-
beforeLeave,
|
|
273
|
-
loadRoute
|
|
274
|
-
};
|
|
275
|
-
}
|
package/dist/history/html.d.ts
DELETED
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
import type { RouterInstance, RouterRawLocation } from '../types';
|
|
2
|
-
import { BaseRouterHistory } from './base';
|
|
3
|
-
export declare class HtmlHistory extends BaseRouterHistory {
|
|
4
|
-
constructor(router: RouterInstance);
|
|
5
|
-
getCurrentLocation(): {
|
|
6
|
-
state: any;
|
|
7
|
-
query?: Record<string, string | undefined>;
|
|
8
|
-
queryArray: Record<string, string[]>;
|
|
9
|
-
params?: Record<string, string>;
|
|
10
|
-
hash?: string;
|
|
11
|
-
path: string;
|
|
12
|
-
base: string;
|
|
13
|
-
};
|
|
14
|
-
onPopState: (e: PopStateEvent) => void;
|
|
15
|
-
init({ replace }?: {
|
|
16
|
-
replace?: boolean;
|
|
17
|
-
}): Promise<void>;
|
|
18
|
-
setupListeners(): void;
|
|
19
|
-
destroy(): void;
|
|
20
|
-
pushWindow(location: RouterRawLocation): void;
|
|
21
|
-
replaceWindow(location: RouterRawLocation): void;
|
|
22
|
-
handleOutside(location: RouterRawLocation, replace?: boolean, isTriggerWithWindow?: boolean): boolean;
|
|
23
|
-
push(location: RouterRawLocation): Promise<void>;
|
|
24
|
-
replace(location: RouterRawLocation): Promise<void>;
|
|
25
|
-
jump(location: RouterRawLocation, replace?: boolean): Promise<void>;
|
|
26
|
-
go(delta: number): void;
|
|
27
|
-
forward(): void;
|
|
28
|
-
protected timer: NodeJS.Timeout | null;
|
|
29
|
-
back(): void;
|
|
30
|
-
}
|