vitarx-router 4.0.0-beta.20 → 4.0.0-beta.22
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/README.md +34 -14
- package/dist/core/common/utils.js +1 -1
- package/dist/core/common/variable.js +1 -1
- package/dist/core/router/manager.d.ts +6 -4
- package/dist/core/router/manager.js +35 -34
- package/dist/core/router/router.js +1 -1
- package/dist/core/router/web.d.ts +13 -0
- package/dist/core/router/web.js +34 -8
- package/dist/core/shared/link.js +1 -1
- package/dist/core/shared/router.d.ts +3 -3
- package/dist/core/shared/router.js +7 -4
- package/dist/core/shared/utils.d.ts +5 -4
- package/dist/core/shared/utils.js +11 -8
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -112,6 +112,25 @@ import { createMemoryRouter } from 'vitarx-router'
|
|
|
112
112
|
createMemoryRouter({ routes })
|
|
113
113
|
```
|
|
114
114
|
|
|
115
|
+
### 手动初始化
|
|
116
|
+
|
|
117
|
+
默认情况下,`createRouter` / `createWebRouter` 会在创建实例后自动初始化路由器(执行初始导航并注册浏览器事件监听)。如果需要延迟初始化,可以使用 `createWebRouter` 并将第二个参数 `autoInit` 设为 `false`,然后手动调用 `init()` 方法。
|
|
118
|
+
|
|
119
|
+
```typescript
|
|
120
|
+
const router = createWebRouter({ routes }, false)
|
|
121
|
+
|
|
122
|
+
// 在合适的时机手动初始化
|
|
123
|
+
router.init()
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
**适用场景:**
|
|
127
|
+
|
|
128
|
+
- 需要在初始化前注册导航守卫
|
|
129
|
+
- 需要在初始化前完成异步配置加载
|
|
130
|
+
- 需要精确控制初始化时机
|
|
131
|
+
|
|
132
|
+
> **注意:** `autoInit` 仅对 Web 路由器有效。
|
|
133
|
+
|
|
115
134
|
## 路由配置
|
|
116
135
|
|
|
117
136
|
### 基本路由
|
|
@@ -468,20 +487,21 @@ declare module 'vitarx-router' {
|
|
|
468
487
|
|
|
469
488
|
### Router 实例方法
|
|
470
489
|
|
|
471
|
-
| 方法 | 说明
|
|
472
|
-
|
|
473
|
-
| `
|
|
474
|
-
| `
|
|
475
|
-
| `
|
|
476
|
-
| `
|
|
477
|
-
| `
|
|
478
|
-
| `
|
|
479
|
-
| `
|
|
480
|
-
| `
|
|
481
|
-
| `
|
|
482
|
-
| `
|
|
483
|
-
| `
|
|
484
|
-
| `
|
|
490
|
+
| 方法 | 说明 |
|
|
491
|
+
|----------------------------|-----------------------|
|
|
492
|
+
| `init()` | 手动初始化路由器(仅 WebRouter) |
|
|
493
|
+
| `push(target)` | 跳转到新路由 |
|
|
494
|
+
| `replace(target)` | 替换当前路由 |
|
|
495
|
+
| `go(delta)` | 前进/后退指定步数 |
|
|
496
|
+
| `back()` | 后退一步 |
|
|
497
|
+
| `forward()` | 前进一步 |
|
|
498
|
+
| `addRoute(route, parent?)` | 添加路由 |
|
|
499
|
+
| `removeRoute(index)` | 移除路由 |
|
|
500
|
+
| `hasRoute(index)` | 检查路由是否存在 |
|
|
501
|
+
| `matchRoute(target)` | 匹配路由 |
|
|
502
|
+
| `beforeEach(guard)` | 添加前置守卫 |
|
|
503
|
+
| `afterEach(callback)` | 添加后置回调 |
|
|
504
|
+
| `destroy()` | 销毁路由器 |
|
|
485
505
|
|
|
486
506
|
### Router 实例属性
|
|
487
507
|
|
|
@@ -71,7 +71,7 @@ export function parseHashContent(hashContent) {
|
|
|
71
71
|
// 同样限制分割数为 2,防止路径中包含 ?
|
|
72
72
|
const [pathname, queryString] = pathAndQuery.split('?', 2);
|
|
73
73
|
// 3. 格式化路径
|
|
74
|
-
path = normalizePath(pathname
|
|
74
|
+
path = pathname ? normalizePath(pathname) : '/';
|
|
75
75
|
// 4. 解析查询参数
|
|
76
76
|
if (queryString) {
|
|
77
77
|
query = parseQuery(queryString);
|
|
@@ -97,7 +97,7 @@ export function mergePathVariable(path, params) {
|
|
|
97
97
|
return String(value).replace(/\s+/g, '_');
|
|
98
98
|
});
|
|
99
99
|
// 使用 formatPath 处理可能出现的双斜杠 (如 /user//) 或首尾斜杠问题
|
|
100
|
-
return normalizePath(fullPath);
|
|
100
|
+
return normalizePath(fullPath, true);
|
|
101
101
|
}
|
|
102
102
|
/**
|
|
103
103
|
* 合并两个路由模式对象
|
|
@@ -9,7 +9,9 @@ export interface RouteManagerOptions {
|
|
|
9
9
|
/**
|
|
10
10
|
* 是否启用严格模式
|
|
11
11
|
*
|
|
12
|
-
*
|
|
12
|
+
* 启用后路径匹配将严格匹配即 /user/ 结尾存在斜杠会匹配失败
|
|
13
|
+
*
|
|
14
|
+
* 禁用后路径匹配将宽匹配即 /user/ 会匹配 /user
|
|
13
15
|
*
|
|
14
16
|
* @default false
|
|
15
17
|
*/
|
|
@@ -23,8 +25,8 @@ export interface RouteManagerOptions {
|
|
|
23
25
|
/**
|
|
24
26
|
* 是否启用索引回退匹配。
|
|
25
27
|
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
+
* 开启后,当访问深层index路径(如 /user/index)未匹配时,
|
|
29
|
+
* 会尝试移除index路径(/user)再次进行匹配。
|
|
28
30
|
* 匹配成功则渲染组件,且保持 URL 不变。
|
|
29
31
|
*
|
|
30
32
|
* 仅支持匹配静态路径,不做动态路径匹配!
|
|
@@ -126,7 +128,7 @@ export declare class RouteManager {
|
|
|
126
128
|
* @returns 规范化后的路径(根据 ignoreCase 配置转换为小写)
|
|
127
129
|
* @private
|
|
128
130
|
*/
|
|
129
|
-
private
|
|
131
|
+
private toLookupPath;
|
|
130
132
|
/**
|
|
131
133
|
* 根据路径查找路由
|
|
132
134
|
*
|
|
@@ -127,7 +127,7 @@ export class RouteManager {
|
|
|
127
127
|
* @returns 规范化后的路径(根据 ignoreCase 配置转换为小写)
|
|
128
128
|
* @private
|
|
129
129
|
*/
|
|
130
|
-
|
|
130
|
+
toLookupPath(path) {
|
|
131
131
|
return this.config.ignoreCase ? path.toLowerCase() : path;
|
|
132
132
|
}
|
|
133
133
|
/**
|
|
@@ -137,7 +137,7 @@ export class RouteManager {
|
|
|
137
137
|
* @returns 路由记录对象,如果未找到则返回 undefined
|
|
138
138
|
*/
|
|
139
139
|
findByPath(path) {
|
|
140
|
-
const normalizedPath = this.
|
|
140
|
+
const normalizedPath = this.toLookupPath(path);
|
|
141
141
|
return this.staticRoutes.get(normalizedPath) ?? this.aliasRoutes.get(normalizedPath) ?? null;
|
|
142
142
|
}
|
|
143
143
|
/**
|
|
@@ -176,55 +176,56 @@ export class RouteManager {
|
|
|
176
176
|
* @returns 匹配结果对象,包含路由记录和解析后的参数;未匹配返回 null
|
|
177
177
|
*/
|
|
178
178
|
matchByPath(path) {
|
|
179
|
-
|
|
180
|
-
|
|
179
|
+
let normalizedPath = path;
|
|
180
|
+
if (normalizedPath.endsWith('/') && normalizedPath !== '/') {
|
|
181
|
+
if (this.config.strict)
|
|
182
|
+
return null;
|
|
183
|
+
normalizedPath = normalizedPath.slice(0, -1);
|
|
181
184
|
}
|
|
182
185
|
// 1. 标准化路径
|
|
183
|
-
const
|
|
184
|
-
const lookupPath = this.config.ignoreCase
|
|
185
|
-
? formattedPath.toLowerCase()
|
|
186
|
-
: formattedPath;
|
|
186
|
+
const lookupPath = this.toLookupPath(normalizedPath);
|
|
187
187
|
// 2. 静态路由精确匹配
|
|
188
188
|
const staticRoute = this.staticRoutes.get(lookupPath);
|
|
189
189
|
if (staticRoute) {
|
|
190
|
-
return { path
|
|
190
|
+
return { path, route: staticRoute, params: {} };
|
|
191
191
|
}
|
|
192
192
|
// 2.5 别名路由精确匹配
|
|
193
193
|
const aliasRoute = this.aliasRoutes.get(lookupPath);
|
|
194
194
|
if (aliasRoute) {
|
|
195
|
-
return { path
|
|
195
|
+
return { path, route: aliasRoute, params: {} };
|
|
196
196
|
}
|
|
197
197
|
// 3. 动态路由匹配
|
|
198
|
-
const
|
|
199
|
-
const
|
|
200
|
-
const
|
|
201
|
-
if (
|
|
202
|
-
for (const { regex, route } of
|
|
198
|
+
const pathSegments = path.split('/').filter(Boolean);
|
|
199
|
+
const segmentCount = pathSegments.length;
|
|
200
|
+
const dynamicCandidates = this.dynamicRoutes.get(segmentCount);
|
|
201
|
+
if (dynamicCandidates) {
|
|
202
|
+
for (const { regex, route } of dynamicCandidates) {
|
|
203
203
|
regex.lastIndex = 0;
|
|
204
204
|
// 执行正则匹配
|
|
205
|
-
const
|
|
206
|
-
if (
|
|
205
|
+
const regexResult = regex.exec(path);
|
|
206
|
+
if (regexResult) {
|
|
207
207
|
const params = {};
|
|
208
208
|
// 解析捕获组参数
|
|
209
209
|
if (route.pattern) {
|
|
210
210
|
for (let i = 0; i < route.pattern.length; i++) {
|
|
211
211
|
const paramDef = route.pattern[i];
|
|
212
|
-
const
|
|
212
|
+
const capturedValue = regexResult[i + 1];
|
|
213
213
|
// 仅当捕获到值时写入 params
|
|
214
|
-
if (
|
|
215
|
-
params[paramDef.name] =
|
|
214
|
+
if (capturedValue !== undefined) {
|
|
215
|
+
params[paramDef.name] = capturedValue;
|
|
216
216
|
}
|
|
217
217
|
}
|
|
218
218
|
}
|
|
219
|
-
return { path
|
|
219
|
+
return { path, route, params };
|
|
220
220
|
}
|
|
221
221
|
}
|
|
222
222
|
}
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
const
|
|
226
|
-
|
|
227
|
-
|
|
223
|
+
// 4. 结尾斜杠索引回退匹配
|
|
224
|
+
if (lookupPath.endsWith('/index') && this.config.fallbackIndex) {
|
|
225
|
+
const fallbackPath = lookupPath.slice(0, -6);
|
|
226
|
+
const fallbackRoute = this.staticRoutes.get(fallbackPath || '/');
|
|
227
|
+
if (fallbackRoute) {
|
|
228
|
+
return { path, route: fallbackRoute, params: {} };
|
|
228
229
|
}
|
|
229
230
|
}
|
|
230
231
|
return null;
|
|
@@ -352,14 +353,14 @@ export class RouteManager {
|
|
|
352
353
|
// 删除当前路由
|
|
353
354
|
this.routes.delete(route);
|
|
354
355
|
// 删除静态路由映射
|
|
355
|
-
this.staticRoutes.delete(this.
|
|
356
|
+
this.staticRoutes.delete(this.toLookupPath(route.path));
|
|
356
357
|
// 删除命名路由映射
|
|
357
358
|
if (route.name)
|
|
358
359
|
this.namedRoutes.delete(route.name);
|
|
359
360
|
// 删除别名映射
|
|
360
361
|
if (route.aliases) {
|
|
361
362
|
for (const alias of route.aliases) {
|
|
362
|
-
this.aliasRoutes.delete(this.
|
|
363
|
+
this.aliasRoutes.delete(this.toLookupPath(alias));
|
|
363
364
|
// 如果别名是动态路由,也需要从 dynamicRoutes 中移除
|
|
364
365
|
if (isVariablePath(alias)) {
|
|
365
366
|
this.removeAliasDynamicRoute(alias, route);
|
|
@@ -460,7 +461,7 @@ export class RouteManager {
|
|
|
460
461
|
record.parent = parent;
|
|
461
462
|
}
|
|
462
463
|
const rawPath = route.path.trim();
|
|
463
|
-
record.path = normalizePath(parent ? `${parent.path}/${rawPath}` : `/${rawPath}
|
|
464
|
+
record.path = normalizePath(parent ? `${parent.path}/${rawPath}` : `/${rawPath}`, true);
|
|
464
465
|
if (route.name) {
|
|
465
466
|
record.name = route.name;
|
|
466
467
|
}
|
|
@@ -511,13 +512,13 @@ export class RouteManager {
|
|
|
511
512
|
aliasPath = parent.path;
|
|
512
513
|
}
|
|
513
514
|
else if (rawAlias.startsWith('/')) {
|
|
514
|
-
aliasPath = normalizePath(rawAlias);
|
|
515
|
+
aliasPath = normalizePath(rawAlias, true);
|
|
515
516
|
}
|
|
516
517
|
else if (!parent) {
|
|
517
|
-
aliasPath = normalizePath(`/${rawAlias}
|
|
518
|
+
aliasPath = normalizePath(`/${rawAlias}`, true);
|
|
518
519
|
}
|
|
519
520
|
else {
|
|
520
|
-
aliasPath = normalizePath(`${parent.path}/${rawAlias}
|
|
521
|
+
aliasPath = normalizePath(`${parent.path}/${rawAlias}`, true);
|
|
521
522
|
}
|
|
522
523
|
record.aliases.push(aliasPath);
|
|
523
524
|
}
|
|
@@ -550,7 +551,7 @@ export class RouteManager {
|
|
|
550
551
|
this.registerDynamicRoute(route, route.fullPattern);
|
|
551
552
|
}
|
|
552
553
|
else {
|
|
553
|
-
const path = this.
|
|
554
|
+
const path = this.toLookupPath(route.path);
|
|
554
555
|
// 检查是否已存在相同路径的路由
|
|
555
556
|
if (this.staticRoutes.has(path)) {
|
|
556
557
|
// 抛出错误:检测到重复的路由路径
|
|
@@ -562,7 +563,6 @@ export class RouteManager {
|
|
|
562
563
|
// 注册别名
|
|
563
564
|
if (route.aliases && route.aliases.length > 0) {
|
|
564
565
|
for (const alias of route.aliases) {
|
|
565
|
-
const aliasPath = this.normalizePath(alias);
|
|
566
566
|
if (isVariablePath(alias)) {
|
|
567
567
|
if (!validateAliasVariables(route.pattern, alias)) {
|
|
568
568
|
throw new Error(`[Router] Alias "${alias}" variables do not match route "${route.path}" pattern`);
|
|
@@ -571,6 +571,7 @@ export class RouteManager {
|
|
|
571
571
|
this.registerDynamicRoute(route, regex, alias);
|
|
572
572
|
}
|
|
573
573
|
else {
|
|
574
|
+
const aliasPath = this.toLookupPath(alias);
|
|
574
575
|
if (route.pattern && route.pattern.length > 0) {
|
|
575
576
|
throw new Error(`[Router] Alias "${alias}" for dynamic route "${route.path}" must contain variables`);
|
|
576
577
|
}
|
|
@@ -965,7 +965,7 @@ export class Router {
|
|
|
965
965
|
const queryStr = stringifyQuery(query);
|
|
966
966
|
const href = `${path}${queryStr}${hashStr}`;
|
|
967
967
|
return this.config.mode === 'hash'
|
|
968
|
-
? normalizePath(`${this.config.base}
|
|
968
|
+
? normalizePath(`${this.config.base}#${href}`)
|
|
969
969
|
: normalizePath(`${this.config.base}${href}`);
|
|
970
970
|
}
|
|
971
971
|
/**
|
|
@@ -2,7 +2,20 @@ import type { RouteLocation, RouterOptions, ScrollPosition, ScrollTarget } from
|
|
|
2
2
|
import { Router } from './router.js';
|
|
3
3
|
export declare class WebRouter extends Router {
|
|
4
4
|
private readonly history;
|
|
5
|
+
private initialized;
|
|
5
6
|
constructor(options: RouterOptions);
|
|
7
|
+
/**
|
|
8
|
+
* 初始化路由器实例。
|
|
9
|
+
*
|
|
10
|
+
* 如果实例已经初始化,则直接返回当前实例以防止重复初始化。
|
|
11
|
+
* 初始化过程中会执行以下操作:
|
|
12
|
+
* 1. 根据目标 URL 执行初始路由替换;
|
|
13
|
+
* 2. 监听 `popstate` 事件,以处理浏览器历史记录返回时的路由恢复;
|
|
14
|
+
* 3. 监听 `hashchange` 事件,以处理浏览器 hash 值变化时的路由恢复。
|
|
15
|
+
*
|
|
16
|
+
* @returns {this} 返回当前路由器实例,支持链式调用。
|
|
17
|
+
*/
|
|
18
|
+
init(): this;
|
|
6
19
|
/**
|
|
7
20
|
* @inheritDoc
|
|
8
21
|
*/
|
package/dist/core/router/web.js
CHANGED
|
@@ -12,6 +12,12 @@ export class WebRouter extends Router {
|
|
|
12
12
|
writable: true,
|
|
13
13
|
value: window.history
|
|
14
14
|
});
|
|
15
|
+
Object.defineProperty(this, "initialized", {
|
|
16
|
+
enumerable: true,
|
|
17
|
+
configurable: true,
|
|
18
|
+
writable: true,
|
|
19
|
+
value: false
|
|
20
|
+
});
|
|
15
21
|
/**
|
|
16
22
|
* 处理浏览器历史记录的返回/前进事件
|
|
17
23
|
*/
|
|
@@ -49,14 +55,6 @@ export class WebRouter extends Router {
|
|
|
49
55
|
this.replace(this.urlToNavigateTarget()).then();
|
|
50
56
|
}
|
|
51
57
|
});
|
|
52
|
-
// 初始化路由
|
|
53
|
-
this.replace(this.urlToNavigateTarget()).then(res => {
|
|
54
|
-
if (__VITARX_DEV__ && res.state !== NavState.success && res.state !== NavState.cancelled) {
|
|
55
|
-
logger.error(`[Router] Initialization failed: ${res.message}`, res);
|
|
56
|
-
}
|
|
57
|
-
});
|
|
58
|
-
// 初始化时监听 popstate 事件,处理历史记录返回时的路由恢复
|
|
59
|
-
window.addEventListener('popstate', this.onPopState);
|
|
60
58
|
if (this.config.mode === 'hash') {
|
|
61
59
|
const { pathname, search, hash } = window.location;
|
|
62
60
|
if (!hash) {
|
|
@@ -64,7 +62,35 @@ export class WebRouter extends Router {
|
|
|
64
62
|
window.location.replace(path);
|
|
65
63
|
}
|
|
66
64
|
}
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* 初始化路由器实例。
|
|
68
|
+
*
|
|
69
|
+
* 如果实例已经初始化,则直接返回当前实例以防止重复初始化。
|
|
70
|
+
* 初始化过程中会执行以下操作:
|
|
71
|
+
* 1. 根据目标 URL 执行初始路由替换;
|
|
72
|
+
* 2. 监听 `popstate` 事件,以处理浏览器历史记录返回时的路由恢复;
|
|
73
|
+
* 3. 监听 `hashchange` 事件,以处理浏览器 hash 值变化时的路由恢复。
|
|
74
|
+
*
|
|
75
|
+
* @returns {this} 返回当前路由器实例,支持链式调用。
|
|
76
|
+
*/
|
|
77
|
+
init() {
|
|
78
|
+
if (this.initialized)
|
|
79
|
+
return this;
|
|
80
|
+
this.initialized = true;
|
|
81
|
+
// 初始化路由
|
|
82
|
+
this.replace(this.urlToNavigateTarget()).then(res => {
|
|
83
|
+
if (__VITARX_DEV__) {
|
|
84
|
+
if (res.state !== NavState.success && res.state !== NavState.cancelled) {
|
|
85
|
+
logger.error(`[WebRouter] Initialization failed: ${res.message}`, res);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
});
|
|
89
|
+
// 初始化时监听 popstate 事件,处理历史记录返回时的路由恢复
|
|
90
|
+
window.addEventListener('popstate', this.onPopState);
|
|
91
|
+
// 监听 hashchange 事件,处理 hash 值变化时的路由恢复
|
|
67
92
|
window.addEventListener('hashchange', this.onHashChange);
|
|
93
|
+
return this;
|
|
68
94
|
}
|
|
69
95
|
/**
|
|
70
96
|
* @inheritDoc
|
package/dist/core/shared/link.js
CHANGED
|
@@ -23,7 +23,6 @@ export declare function createRouteManager(routes: Route[], options?: RouteManag
|
|
|
23
23
|
* 创建Web模式路由实例
|
|
24
24
|
*
|
|
25
25
|
* @param options - 路由配置选项
|
|
26
|
-
* @param {RouterOptions} options - 路由配置选项
|
|
27
26
|
* @param options.routes - 路由配置表或管理器
|
|
28
27
|
* @param [options.base] - 基础路径
|
|
29
28
|
* @param [options.mode] - URL模式
|
|
@@ -33,9 +32,10 @@ export declare function createRouteManager(routes: Route[], options?: RouteManag
|
|
|
33
32
|
* @param [options.afterEach] - 全局后置钩子
|
|
34
33
|
* @param [options.missing] - 未匹配时要渲染的组件
|
|
35
34
|
* @param [options.onNotFound] - 导航不匹配时触发的回调函数
|
|
35
|
+
* @param [autoInit=true] - 是否自动初始化路由器
|
|
36
36
|
* @returns {WebRouter} 返回Web模式路由实例
|
|
37
37
|
*/
|
|
38
|
-
export declare function createWebRouter(options: RouterOptions): WebRouter;
|
|
38
|
+
export declare function createWebRouter(options: RouterOptions, autoInit?: boolean): WebRouter;
|
|
39
39
|
/**
|
|
40
40
|
* 创建内存模式路由实例
|
|
41
41
|
*
|
|
@@ -66,7 +66,7 @@ export declare function createMemoryRouter(options: RouterOptions): MemoryRouter
|
|
|
66
66
|
* @param [options.afterEach] - 全局后置钩子
|
|
67
67
|
* @param [options.missing] - 未匹配时要渲染的组件
|
|
68
68
|
* @param [options.onNotFound] - 导航不匹配时触发的回调函数
|
|
69
|
-
* @param
|
|
69
|
+
* @param [skipEnvWarn=false] - 是否跳过浏览器检查
|
|
70
70
|
* @returns {Router} 返回路由实例,根据环境返回不同类型的路由
|
|
71
71
|
*
|
|
72
72
|
*/
|
|
@@ -27,7 +27,6 @@ export function createRouteManager(routes, options) {
|
|
|
27
27
|
* 创建Web模式路由实例
|
|
28
28
|
*
|
|
29
29
|
* @param options - 路由配置选项
|
|
30
|
-
* @param {RouterOptions} options - 路由配置选项
|
|
31
30
|
* @param options.routes - 路由配置表或管理器
|
|
32
31
|
* @param [options.base] - 基础路径
|
|
33
32
|
* @param [options.mode] - URL模式
|
|
@@ -37,10 +36,14 @@ export function createRouteManager(routes, options) {
|
|
|
37
36
|
* @param [options.afterEach] - 全局后置钩子
|
|
38
37
|
* @param [options.missing] - 未匹配时要渲染的组件
|
|
39
38
|
* @param [options.onNotFound] - 导航不匹配时触发的回调函数
|
|
39
|
+
* @param [autoInit=true] - 是否自动初始化路由器
|
|
40
40
|
* @returns {WebRouter} 返回Web模式路由实例
|
|
41
41
|
*/
|
|
42
|
-
export function createWebRouter(options) {
|
|
43
|
-
|
|
42
|
+
export function createWebRouter(options, autoInit = true) {
|
|
43
|
+
const instance = new WebRouter(options);
|
|
44
|
+
if (autoInit)
|
|
45
|
+
instance.init();
|
|
46
|
+
return instance;
|
|
44
47
|
}
|
|
45
48
|
/**
|
|
46
49
|
* 创建内存模式路由实例
|
|
@@ -74,7 +77,7 @@ export function createMemoryRouter(options) {
|
|
|
74
77
|
* @param [options.afterEach] - 全局后置钩子
|
|
75
78
|
* @param [options.missing] - 未匹配时要渲染的组件
|
|
76
79
|
* @param [options.onNotFound] - 导航不匹配时触发的回调函数
|
|
77
|
-
* @param
|
|
80
|
+
* @param [skipEnvWarn=false] - 是否跳过浏览器检查
|
|
78
81
|
* @returns {Router} 返回路由实例,根据环境返回不同类型的路由
|
|
79
82
|
*
|
|
80
83
|
*/
|
|
@@ -17,19 +17,20 @@ export declare function stringifyQuery(obj: Record<string, string>): `?${string}
|
|
|
17
17
|
/**
|
|
18
18
|
* 归一化path
|
|
19
19
|
*
|
|
20
|
-
*
|
|
20
|
+
* 去除所有空格、替换重复的斜杠
|
|
21
21
|
*
|
|
22
22
|
* @example
|
|
23
23
|
* normalizePath('/ foo') // '/foo'
|
|
24
|
-
* normalizePath('/foo/') // '/foo'
|
|
24
|
+
* normalizePath('/foo/') // '/foo/'
|
|
25
25
|
* normalizePath('/foo/bar') // '/foo/bar'
|
|
26
26
|
* normalizePath('foo/') // '/foo'
|
|
27
|
+
* normalizePath('/foo/',true) // '/foo'
|
|
27
28
|
*
|
|
28
29
|
* @param {string} path - 路径字符串
|
|
29
|
-
* @param
|
|
30
|
+
* @param {boolean} removeEndSlash - 是否去除尾随斜杠
|
|
30
31
|
* @return {string} - 格式化后的路径字符串
|
|
31
32
|
*/
|
|
32
|
-
export declare function normalizePath(path: string,
|
|
33
|
+
export declare function normalizePath(path: string, removeEndSlash?: boolean): `/${string}`;
|
|
33
34
|
/**
|
|
34
35
|
* 克隆路由位置对象
|
|
35
36
|
*
|
|
@@ -28,24 +28,27 @@ export function stringifyQuery(obj) {
|
|
|
28
28
|
/**
|
|
29
29
|
* 归一化path
|
|
30
30
|
*
|
|
31
|
-
*
|
|
31
|
+
* 去除所有空格、替换重复的斜杠
|
|
32
32
|
*
|
|
33
33
|
* @example
|
|
34
34
|
* normalizePath('/ foo') // '/foo'
|
|
35
|
-
* normalizePath('/foo/') // '/foo'
|
|
35
|
+
* normalizePath('/foo/') // '/foo/'
|
|
36
36
|
* normalizePath('/foo/bar') // '/foo/bar'
|
|
37
37
|
* normalizePath('foo/') // '/foo'
|
|
38
|
+
* normalizePath('/foo/',true) // '/foo'
|
|
38
39
|
*
|
|
39
40
|
* @param {string} path - 路径字符串
|
|
40
|
-
* @param
|
|
41
|
+
* @param {boolean} removeEndSlash - 是否去除尾随斜杠
|
|
41
42
|
* @return {string} - 格式化后的路径字符串
|
|
42
43
|
*/
|
|
43
|
-
export function normalizePath(path,
|
|
44
|
+
export function normalizePath(path, removeEndSlash = false) {
|
|
44
45
|
// 去除所有空格 处理重复//
|
|
45
|
-
|
|
46
|
-
if (
|
|
47
|
-
|
|
48
|
-
|
|
46
|
+
let normalizedPath = `/${path.trim()}`.replace(/\s+/g, '').replace(/\/+/g, '/');
|
|
47
|
+
if (removeEndSlash && normalizedPath.endsWith('/') && normalizedPath !== '/') {
|
|
48
|
+
normalizedPath = normalizedPath.replace(/\/$/, '');
|
|
49
|
+
}
|
|
50
|
+
// 去除尾随斜杠
|
|
51
|
+
return normalizedPath;
|
|
49
52
|
}
|
|
50
53
|
/**
|
|
51
54
|
* 克隆路由位置对象
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vitarx-router",
|
|
3
|
-
"version": "4.0.0-beta.
|
|
3
|
+
"version": "4.0.0-beta.22",
|
|
4
4
|
"description": "Official routing solution for Vitarx framework with declarative routing, navigation guards, dynamic routes, file-based routing with HMR, and full TypeScript support.",
|
|
5
5
|
"author": "ZhuChonglin <8210856@qq.com>",
|
|
6
6
|
"license": "MIT",
|
|
@@ -80,7 +80,7 @@
|
|
|
80
80
|
"typecheck": "tsc -p tsconfig.build.json --noEmit",
|
|
81
81
|
"check:circular": "madge --extensions js --circular dist --warning --exclude '.*\\.d\\.ts$'",
|
|
82
82
|
"test": "vitest run",
|
|
83
|
-
"test:core": "vitest run --project
|
|
83
|
+
"test:core": "vitest run --project core",
|
|
84
84
|
"test:plugin-vite": "vitest run --project plugin-vite",
|
|
85
85
|
"test:watch": "vitest watch",
|
|
86
86
|
"test:coverage": "vitest run --coverage",
|