vitarx-router 4.0.0-beta.13 → 4.0.0-beta.14

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.
@@ -12,7 +12,7 @@ import { __ROUTER_VIEW_DEPTH_KEY__, useRouter } from '../core/index.js';
12
12
  * @returns {View} 返回渲染的视图
13
13
  */
14
14
  export function RouterView(props) {
15
- const { children, name = 'default' } = props;
15
+ const { children } = props;
16
16
  // 获取路由实例
17
17
  const router = useRouter();
18
18
  // 获取父级 index
@@ -20,6 +20,7 @@ export function RouterView(props) {
20
20
  const index = parentIndex + 1; // 计算当前视图的索引
21
21
  provide(__ROUTER_VIEW_DEPTH_KEY__, index); // 向子组件提供当前索引
22
22
  // 匹配的路由线路
23
+ const viewName = computed(() => props.name || 'default');
23
24
  const matchedRoute = computed(() => {
24
25
  return router.route.matched[index] ?? null;
25
26
  });
@@ -28,8 +29,7 @@ export function RouterView(props) {
28
29
  const currentRoute = matchedRoute.value;
29
30
  if (!currentRoute)
30
31
  return null;
31
- const name = props.name || 'default'; // 获取视图名称,默认为 'default'
32
- let injectProps = currentRoute.props?.[name] ?? router.config.props ?? false;
32
+ let injectProps = currentRoute.props?.[viewName.value] ?? router.config.props ?? false;
33
33
  if (injectProps === false)
34
34
  return null; // 如果属性为 false,返回null
35
35
  if (injectProps === true && currentRoute.pattern) {
@@ -52,7 +52,7 @@ export function RouterView(props) {
52
52
  const route = matchedRoute.value; // 获取匹配的路由记录
53
53
  if (!route)
54
54
  return null;
55
- return route.component?.[name] ?? null;
55
+ return route.component?.[viewName.value] ?? null;
56
56
  });
57
57
  // 如果传入了 children 函数,则调用并返回其结果
58
58
  if (isFunction(children)) {
@@ -61,6 +61,7 @@ export function RouterView(props) {
61
61
  }
62
62
  catch (e) {
63
63
  logger.error('[RouterView] Error occurred while executing children function', e);
64
+ return createCommentView(`router-view:error`);
64
65
  }
65
66
  }
66
67
  let lastView = null;
@@ -2,12 +2,11 @@
2
2
  * 导航状态
3
3
  *
4
4
  * 枚举值:
5
- * 0. success: 导航成功
6
- * 1. aborted: 导航被阻止
7
- * 2. cancelled: 导航被取消
8
- * 3. duplicated: 重复导航
9
- * 4. notfound: 路由未匹配
10
- * 5. exception: 捕获到异常
5
+ * 1. success: 导航成功
6
+ * 2. aborted: 导航被阻止
7
+ * 4. cancelled: 导航被取消
8
+ * 8. duplicated: 重复导航
9
+ * 16. notfound: 路由未匹配
11
10
  */
12
11
  export declare enum NavState {
13
12
  /**
@@ -2,12 +2,11 @@
2
2
  * 导航状态
3
3
  *
4
4
  * 枚举值:
5
- * 0. success: 导航成功
6
- * 1. aborted: 导航被阻止
7
- * 2. cancelled: 导航被取消
8
- * 3. duplicated: 重复导航
9
- * 4. notfound: 路由未匹配
10
- * 5. exception: 捕获到异常
5
+ * 1. success: 导航成功
6
+ * 2. aborted: 导航被阻止
7
+ * 4. cancelled: 导航被取消
8
+ * 8. duplicated: 重复导航
9
+ * 16. notfound: 路由未匹配
11
10
  */
12
11
  export var NavState;
13
12
  (function (NavState) {
@@ -1,4 +1,5 @@
1
1
  import { isString, logger } from 'vitarx';
2
+ import { NavState } from '../common/constant.js';
2
3
  import { parseHashContent } from '../common/utils.js';
3
4
  import { normalizePath, parseQuery } from '../shared/utils.js';
4
5
  import { Router } from './router.js';
@@ -49,7 +50,11 @@ export class WebRouter extends Router {
49
50
  }
50
51
  });
51
52
  // 初始化路由
52
- this.replace(this.urlToNavigateTarget()).then();
53
+ this.replace(this.urlToNavigateTarget()).then(res => {
54
+ if (res.state !== NavState.success) {
55
+ logger.error(`[Router] Initialization failed: ${res.message}`, res);
56
+ }
57
+ });
53
58
  // 初始化时监听 popstate 事件,处理历史记录返回时的路由恢复
54
59
  window.addEventListener('popstate', this.onPopState);
55
60
  if (this.config.mode === 'hash') {
@@ -194,7 +194,7 @@ export class FileRouter {
194
194
  */
195
195
  processFile(filePath, page, pageMapping, parent) {
196
196
  // 分离出路由 path 和视图命名
197
- const { routePath, viewName = 'default' } = parseRoutePath(filePath, this.config.pathParser);
197
+ const { routePath, viewName } = parseRoutePath(filePath, this.config.pathParser);
198
198
  const fileType = this.getPageType(filePath, routePath, page);
199
199
  if (fileType === 'ignore')
200
200
  return null;
@@ -1,4 +1,4 @@
1
- import type { PathParser, PathParseResult } from '../types/index.js';
1
+ import type { PathParser } from '../types/index.js';
2
2
  /**
3
3
  * 路径解析错误类
4
4
  *
@@ -22,6 +22,13 @@ export declare class PathParseError extends TypeError {
22
22
  */
23
23
  toString(): string;
24
24
  }
25
+ /**
26
+ * 解析结果接口
27
+ */
28
+ interface ParseResult {
29
+ routePath: string;
30
+ viewName: string;
31
+ }
25
32
  /**
26
33
  * 解析路由路径和视图名称
27
34
  *
@@ -32,4 +39,5 @@ export declare class PathParseError extends TypeError {
32
39
  * @returns 路由路径和视图名称
33
40
  * @throws {PathParseError} 当路径解析失败时抛出
34
41
  */
35
- export declare function parseRoutePath(filePath: string, parser?: PathParser): Exclude<PathParseResult, string>;
42
+ export declare function parseRoutePath(filePath: string, parser?: PathParser): ParseResult;
43
+ export {};
@@ -74,10 +74,10 @@ export class PathParseError extends TypeError {
74
74
  export function parseRoutePath(filePath, parser) {
75
75
  const { basename } = extractFileInfo(filePath);
76
76
  if (!parser) {
77
- return parseDefaultRoutePath(basename);
77
+ return defaultPathParser(basename);
78
78
  }
79
79
  const result = parser(basename, filePath);
80
- return parseCustomRouteResult(result, filePath);
80
+ return parseCustomResult(result, filePath);
81
81
  }
82
82
  /**
83
83
  * 提取文件信息
@@ -96,24 +96,32 @@ function extractFileInfo(filePath) {
96
96
  * @param basename - 文件基本名称
97
97
  * @returns 解析结果
98
98
  */
99
- function parseDefaultRoutePath(basename) {
100
- const [routePath, viewName] = basename.split('@', 2);
99
+ function defaultPathParser(basename) {
100
+ const [rawPath, viewName] = basename.split('@', 2);
101
+ const routePath = normalizeRoutePath(rawPath);
102
+ if (!routePath) {
103
+ throw new PathParseError('pathParser returned empty routePath', {
104
+ filePath: basename,
105
+ originalValue: rawPath,
106
+ field: 'routePath'
107
+ });
108
+ }
101
109
  return {
102
110
  routePath,
103
111
  viewName: viewName || 'default'
104
112
  };
105
113
  }
106
114
  /**
107
- * 解析自定义路由结果
115
+ * 解析自定义解析器结果
108
116
  *
109
117
  * @param result - 解析器返回的结果
110
118
  * @param filePath - 文件路径(用于错误上下文)
111
119
  * @returns 解析结果
112
120
  * @throws {PathParseError} 当结果无效时抛出
113
121
  */
114
- function parseCustomRouteResult(result, filePath) {
122
+ function parseCustomResult(result, filePath) {
115
123
  if (typeof result === 'string') {
116
- return parseStringResult(result, filePath);
124
+ return defaultPathParser(result);
117
125
  }
118
126
  if (result && typeof result === 'object' && !Array.isArray(result)) {
119
127
  return parseObjectResult(result, filePath);
@@ -124,25 +132,6 @@ function parseCustomRouteResult(result, filePath) {
124
132
  field: 'result'
125
133
  });
126
134
  }
127
- /**
128
- * 解析字符串类型的结果
129
- *
130
- * @param result - 字符串结果
131
- * @param filePath - 文件路径
132
- * @returns 解析结果
133
- * @throws {PathParseError} 当路径无效时抛出
134
- */
135
- function parseStringResult(result, filePath) {
136
- const routePath = normalizeRoutePath(result);
137
- if (!routePath) {
138
- throw new PathParseError('pathParser returned empty routePath', {
139
- filePath,
140
- originalValue: result,
141
- field: 'routePath'
142
- });
143
- }
144
- return { routePath, viewName: 'default' };
145
- }
146
135
  /**
147
136
  * 解析对象类型的结果
148
137
  *
@@ -210,11 +199,14 @@ function validateViewName(viewName, filePath) {
210
199
  /**
211
200
  * 标准化路由路径
212
201
  *
213
- * 去除路径首尾空白和开头的斜杠。
202
+ * 去除路径首尾空白和首尾的斜杠,将 . # 等不利于 URL 的字符替换为 -。
214
203
  *
215
204
  * @param routePath - 原始路由路径
216
205
  * @returns 标准化后的路由路径
217
206
  */
218
207
  function normalizeRoutePath(routePath) {
219
- return routePath.trim().replace(/^\/+/, '');
208
+ return routePath
209
+ .trim()
210
+ .replace(/^\/+|\/+$/g, '')
211
+ .replace(/[.#]/g, '-');
220
212
  }
@@ -52,11 +52,14 @@ export type PathStrategy = 'kebab' | 'lowercase' | 'raw';
52
52
  export type PageSource = string | PageDirOptions;
53
53
  /**
54
54
  * 路径解析结果
55
+ *
56
+ * - string: 文件名称,交由内置默认的pathParser继续处理。
57
+ * - `{ routePath: string, viewName?: string }`: 路径和视图名称
55
58
  */
56
59
  export type PathParseResult = string | {
57
- /** 解析后的路径 */
60
+ /** 解析后的路径 如:home.jsx -> 'home' */
58
61
  routePath: string;
59
- /** 视图名称 */
62
+ /** 视图名称 如:home.nav.jsx -> 'nav' */
60
63
  viewName?: string;
61
64
  };
62
65
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vitarx-router",
3
- "version": "4.0.0-beta.13",
3
+ "version": "4.0.0-beta.14",
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",