vitarx-router 3.0.0-alpha.2 → 3.0.0
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/dist/vitarx-router.es.js +123 -142
- package/dist/vitarx-router.iife.js +1 -0
- package/package.json +12 -20
- package/dist/vitarx-router.umd.js +0 -1
- package/index.mjs +0 -1
package/dist/vitarx-router.es.js
CHANGED
|
@@ -1,6 +1,3 @@
|
|
|
1
|
-
var __defProp = Object.defineProperty;
|
|
2
|
-
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: !0, configurable: !0, writable: !0, value }) : obj[key] = value;
|
|
3
|
-
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key != "symbol" ? key + "" : key, value);
|
|
4
1
|
import { deepClone, reactive, markRaw, shallowReactive, readonly, createElement, isDeepEqual, isRecordObject, isObject, Widget, shallowRef, inject, provide, watch, toRaw, Observer, Computed, isString } from "vitarx";
|
|
5
2
|
var NavigateStatus = /* @__PURE__ */ ((NavigateStatus2) => (NavigateStatus2[NavigateStatus2.success = 0] = "success", NavigateStatus2[NavigateStatus2.aborted = 1] = "aborted", NavigateStatus2[NavigateStatus2.cancelled = 2] = "cancelled", NavigateStatus2[NavigateStatus2.duplicated = 3] = "duplicated", NavigateStatus2[NavigateStatus2.not_matched = 4] = "not_matched", NavigateStatus2[NavigateStatus2.exception = 5] = "exception", NavigateStatus2))(NavigateStatus || {});
|
|
6
3
|
function isVariablePath(path) {
|
|
@@ -163,20 +160,20 @@ function normalizeRoute(route, group, suffix) {
|
|
|
163
160
|
);
|
|
164
161
|
if (!route.path.trim())
|
|
165
162
|
throw new TypeError("[Vitarx.Router][TYPE_ERROR]:路由线路配置 path 不能为空");
|
|
166
|
-
return route.path = formatPath(group ? `${group.path}/${route.path}` : route.path), normalizeRouteWidget(route), normalizeInjectProps(route), route.suffix
|
|
163
|
+
return route.path = formatPath(group ? `${group.path}/${route.path}` : route.path), normalizeRouteWidget(route), normalizeInjectProps(route), route.suffix ??= group?.suffix ?? suffix, route.afterEnter ??= group?.afterEnter, route.beforeEnter ??= group?.beforeEnter, route;
|
|
167
164
|
}
|
|
168
165
|
class RouterRegistry {
|
|
166
|
+
// 配置
|
|
167
|
+
_options;
|
|
168
|
+
// 命名路由映射
|
|
169
|
+
_namedRoutes = /* @__PURE__ */ new Map();
|
|
170
|
+
// 动态路由正则,按长度分组
|
|
171
|
+
_dynamicRoutes = /* @__PURE__ */ new Map();
|
|
172
|
+
// 路由path映射
|
|
173
|
+
_pathRoutes = /* @__PURE__ */ new Map();
|
|
174
|
+
// 父路由映射
|
|
175
|
+
_parentRoute = /* @__PURE__ */ new WeakMap();
|
|
169
176
|
constructor(options) {
|
|
170
|
-
// 配置
|
|
171
|
-
__publicField(this, "_options");
|
|
172
|
-
// 命名路由映射
|
|
173
|
-
__publicField(this, "_namedRoutes", /* @__PURE__ */ new Map());
|
|
174
|
-
// 动态路由正则,按长度分组
|
|
175
|
-
__publicField(this, "_dynamicRoutes", /* @__PURE__ */ new Map());
|
|
176
|
-
// 路由path映射
|
|
177
|
-
__publicField(this, "_pathRoutes", /* @__PURE__ */ new Map());
|
|
178
|
-
// 父路由映射
|
|
179
|
-
__publicField(this, "_parentRoute", /* @__PURE__ */ new WeakMap());
|
|
180
177
|
const config = {
|
|
181
178
|
base: "/",
|
|
182
179
|
strict: !1,
|
|
@@ -370,7 +367,7 @@ class RouterRegistry {
|
|
|
370
367
|
*/
|
|
371
368
|
removedFromRoutes(route) {
|
|
372
369
|
const parent = this.findParentRoute(route);
|
|
373
|
-
if (parent
|
|
370
|
+
if (parent?.children) {
|
|
374
371
|
const index2 = parent.children.indexOf(route);
|
|
375
372
|
index2 !== -1 && parent.children.splice(index2, 1);
|
|
376
373
|
}
|
|
@@ -412,13 +409,12 @@ class RouterRegistry {
|
|
|
412
409
|
for (const child of normalizedRoute.children)
|
|
413
410
|
this.registerRoute(child, normalizedRoute);
|
|
414
411
|
normalizedRoute.redirect || (normalizedRoute.redirect = function(to) {
|
|
415
|
-
var _a;
|
|
416
412
|
let first = normalizedRoute.children[0];
|
|
417
413
|
for (; first; ) {
|
|
418
414
|
if (first.redirect)
|
|
419
415
|
return typeof first.redirect == "function" ? first.redirect.call(this, to) : first.redirect;
|
|
420
416
|
if (first.widget) return { index: first.path };
|
|
421
|
-
first =
|
|
417
|
+
first = first.children?.[0];
|
|
422
418
|
}
|
|
423
419
|
console.error(
|
|
424
420
|
`[Vitarx.Router][ERROR]:${normalizedRoute.path} 分组路由在没有配置重定向的情况下,它的第一个子路由必须具有widget或redirect,否则无法匹配视图`,
|
|
@@ -495,7 +491,37 @@ function diffUpdateProps(oldProps, newProps) {
|
|
|
495
491
|
delete oldProps[key];
|
|
496
492
|
return changes;
|
|
497
493
|
}
|
|
498
|
-
|
|
494
|
+
class RouterCore extends RouterRegistry {
|
|
495
|
+
// 当前执行的导航任务ID,用于处理并发导航请求
|
|
496
|
+
_currentTaskId = null;
|
|
497
|
+
// 任务计数器,用于生成唯一的任务ID
|
|
498
|
+
_taskCounter = 0;
|
|
499
|
+
/**
|
|
500
|
+
* 等待执行的 replace 操作数据
|
|
501
|
+
* 如果不为 null,表示当前有一个等待完成的 replace 导航
|
|
502
|
+
*/
|
|
503
|
+
_pendingReplace = null;
|
|
504
|
+
/**
|
|
505
|
+
* 等待执行的 push 操作数据
|
|
506
|
+
* 如果不为 null,表示当前有一个等待完成的 push 导航
|
|
507
|
+
*/
|
|
508
|
+
_pendingPush = null;
|
|
509
|
+
/**
|
|
510
|
+
* 滚动行为处理器
|
|
511
|
+
* 用于自定义路由切换时的滚动行为
|
|
512
|
+
*/
|
|
513
|
+
_scrollBehaviorHandler = void 0;
|
|
514
|
+
/**
|
|
515
|
+
* 当前路由数据
|
|
516
|
+
* 包含当前路由的完整信息,如路径、参数、查询字符串等
|
|
517
|
+
*/
|
|
518
|
+
_currentRouteLocation;
|
|
519
|
+
/**
|
|
520
|
+
* 只读路由位置数据
|
|
521
|
+
*
|
|
522
|
+
* @private
|
|
523
|
+
*/
|
|
524
|
+
_readonlyRouteLocation;
|
|
499
525
|
/**
|
|
500
526
|
* 路由器构造函数
|
|
501
527
|
* 初始化路由器并确保单例
|
|
@@ -504,50 +530,9 @@ const _RouterCore = class _RouterCore extends RouterRegistry {
|
|
|
504
530
|
* @throws {Error} 如果已存在路由器实例则抛出错误
|
|
505
531
|
*/
|
|
506
532
|
constructor(options) {
|
|
507
|
-
if (
|
|
533
|
+
if (RouterCore._instance)
|
|
508
534
|
throw new Error("[Vitarx.Router.constructor]:路由器实例已存在,不能创建多个实例");
|
|
509
|
-
super(options)
|
|
510
|
-
// 当前执行的导航任务ID,用于处理并发导航请求
|
|
511
|
-
__publicField(this, "_currentTaskId", null);
|
|
512
|
-
// 任务计数器,用于生成唯一的任务ID
|
|
513
|
-
__publicField(this, "_taskCounter", 0);
|
|
514
|
-
/**
|
|
515
|
-
* 等待执行的 replace 操作数据
|
|
516
|
-
* 如果不为 null,表示当前有一个等待完成的 replace 导航
|
|
517
|
-
*/
|
|
518
|
-
__publicField(this, "_pendingReplace", null);
|
|
519
|
-
/**
|
|
520
|
-
* 等待执行的 push 操作数据
|
|
521
|
-
* 如果不为 null,表示当前有一个等待完成的 push 导航
|
|
522
|
-
*/
|
|
523
|
-
__publicField(this, "_pendingPush", null);
|
|
524
|
-
/**
|
|
525
|
-
* 滚动行为处理器
|
|
526
|
-
* 用于自定义路由切换时的滚动行为
|
|
527
|
-
*/
|
|
528
|
-
__publicField(this, "_scrollBehaviorHandler");
|
|
529
|
-
/**
|
|
530
|
-
* 当前路由数据
|
|
531
|
-
* 包含当前路由的完整信息,如路径、参数、查询字符串等
|
|
532
|
-
*/
|
|
533
|
-
__publicField(this, "_currentRouteLocation");
|
|
534
|
-
/**
|
|
535
|
-
* 只读路由位置数据
|
|
536
|
-
*
|
|
537
|
-
* @private
|
|
538
|
-
*/
|
|
539
|
-
__publicField(this, "_readonlyRouteLocation");
|
|
540
|
-
/**
|
|
541
|
-
* 是否运行在浏览器环境
|
|
542
|
-
* 用于区分服务端渲染和客户端渲染
|
|
543
|
-
*/
|
|
544
|
-
__publicField(this, "_isBrowser", typeof window < "u" && typeof window.document < "u");
|
|
545
|
-
/**
|
|
546
|
-
* 滚动行为
|
|
547
|
-
* 定义路由切换时的滚动效果
|
|
548
|
-
*/
|
|
549
|
-
__publicField(this, "_scrollBehavior", "auto");
|
|
550
|
-
this._currentRouteLocation = reactive({
|
|
535
|
+
super(options), this._currentRouteLocation = reactive({
|
|
551
536
|
index: this._options.base,
|
|
552
537
|
path: this._options.base,
|
|
553
538
|
hash: "",
|
|
@@ -559,6 +544,11 @@ const _RouterCore = class _RouterCore extends RouterRegistry {
|
|
|
559
544
|
suffix: ""
|
|
560
545
|
}), this._readonlyRouteLocation = readonly(this._currentRouteLocation);
|
|
561
546
|
}
|
|
547
|
+
/**
|
|
548
|
+
* 路由器单例实例
|
|
549
|
+
* 用于全局存储唯一的路由器实例
|
|
550
|
+
*/
|
|
551
|
+
static _instance;
|
|
562
552
|
/**
|
|
563
553
|
* 获取路由器单例实例
|
|
564
554
|
*
|
|
@@ -566,9 +556,9 @@ const _RouterCore = class _RouterCore extends RouterRegistry {
|
|
|
566
556
|
* @return {RouterCore} 路由器实例
|
|
567
557
|
*/
|
|
568
558
|
static get instance() {
|
|
569
|
-
if (!
|
|
559
|
+
if (!RouterCore._instance)
|
|
570
560
|
throw new Error("[Vitarx.Router.instance]:路由器实例未初始化");
|
|
571
|
-
return
|
|
561
|
+
return RouterCore._instance;
|
|
572
562
|
}
|
|
573
563
|
/**
|
|
574
564
|
* 判断路由器是否初始化完成
|
|
@@ -578,14 +568,24 @@ const _RouterCore = class _RouterCore extends RouterRegistry {
|
|
|
578
568
|
* @return {boolean} - 如果初始化完成,返回true,否则返回false
|
|
579
569
|
*/
|
|
580
570
|
get initialized() {
|
|
581
|
-
return
|
|
571
|
+
return RouterCore._instance !== void 0;
|
|
582
572
|
}
|
|
573
|
+
/**
|
|
574
|
+
* 是否运行在浏览器环境
|
|
575
|
+
* 用于区分服务端渲染和客户端渲染
|
|
576
|
+
*/
|
|
577
|
+
_isBrowser = typeof window < "u" && typeof window.document < "u";
|
|
583
578
|
/**
|
|
584
579
|
* 是否运行在浏览器端
|
|
585
580
|
*/
|
|
586
581
|
get isBrowser() {
|
|
587
582
|
return this._isBrowser;
|
|
588
583
|
}
|
|
584
|
+
/**
|
|
585
|
+
* 滚动行为
|
|
586
|
+
* 定义路由切换时的滚动效果
|
|
587
|
+
*/
|
|
588
|
+
_scrollBehavior = "auto";
|
|
589
589
|
/**
|
|
590
590
|
* 滚动行为
|
|
591
591
|
*
|
|
@@ -694,7 +694,7 @@ const _RouterCore = class _RouterCore extends RouterRegistry {
|
|
|
694
694
|
* @return {this} - 返回当前路由器实例
|
|
695
695
|
*/
|
|
696
696
|
initialize() {
|
|
697
|
-
return
|
|
697
|
+
return RouterCore._instance ? this : (this.setupRoutes(this._options.routes), typeof this.options.scrollBehavior == "function" ? this._scrollBehaviorHandler = this.options.scrollBehavior : this._scrollBehavior = this.options.scrollBehavior, this.initializeRouter(), RouterCore._instance = this, this);
|
|
698
698
|
}
|
|
699
699
|
/**
|
|
700
700
|
* 此方法用于浏览器端滚动到指定位置
|
|
@@ -738,7 +738,7 @@ const _RouterCore = class _RouterCore extends RouterRegistry {
|
|
|
738
738
|
parent.widget && matched.unshift(parent), parent = this.findParentRoute(parent);
|
|
739
739
|
matched.push(route);
|
|
740
740
|
}
|
|
741
|
-
const meta = route
|
|
741
|
+
const meta = route?.meta ? deepClone(route.meta) : {}, hashStr = formatHash(hash), suffix = getPathSuffix(index), fullPath = this.makeFullPath(path, query, hashStr, suffix);
|
|
742
742
|
return { index, path, hash: hashStr, fullPath, params, query, matched, meta, suffix };
|
|
743
743
|
}
|
|
744
744
|
/**
|
|
@@ -772,7 +772,7 @@ const _RouterCore = class _RouterCore extends RouterRegistry {
|
|
|
772
772
|
message: "仅hash变化,导航成功!"
|
|
773
773
|
});
|
|
774
774
|
const matched = to.matched.at(-1);
|
|
775
|
-
if (matched
|
|
775
|
+
if (matched?.redirect) {
|
|
776
776
|
let redirectTarget;
|
|
777
777
|
if (typeof matched.redirect == "object" && matched.redirect.index)
|
|
778
778
|
redirectTarget = matched.redirect;
|
|
@@ -782,14 +782,14 @@ const _RouterCore = class _RouterCore extends RouterRegistry {
|
|
|
782
782
|
const redirectHandleResult = matched.redirect.call(this, to);
|
|
783
783
|
isObject(redirectHandleResult) && (redirectTarget = redirectHandleResult);
|
|
784
784
|
}
|
|
785
|
-
if (redirectTarget
|
|
785
|
+
if (redirectTarget?.index) return performNavigation(redirectTarget, !0);
|
|
786
786
|
}
|
|
787
787
|
try {
|
|
788
788
|
const result = await this.onBeforeEach(to, from);
|
|
789
789
|
return result === !1 ? createNavigateResult({
|
|
790
790
|
status: NavigateStatus.aborted,
|
|
791
791
|
message: `导航到${to.index}目标时被前置守卫钩子阻止!`
|
|
792
|
-
}) : isCurrentTask() ? typeof result == "object" && result.index !== _target.index ? (result.isReplace
|
|
792
|
+
}) : isCurrentTask() ? typeof result == "object" && result.index !== _target.index ? (result.isReplace ??= !1, performNavigation(result, !0)) : typeof result == "string" && result !== _target.index ? performNavigation({ index: result, isReplace: !1 }, !0) : !to.matched.length && !this.missing ? createNavigateResult({
|
|
793
793
|
status: NavigateStatus.not_matched,
|
|
794
794
|
message: `未匹配到任何路由规则,被系统阻止!请检测目标索引(${to.index})是否已注册路由。`
|
|
795
795
|
}) : ("isReplace" in _target && _target.isReplace ? (this._pendingReplace = to, this.replaceHistory(to)) : (this._pendingPush = to, this.pushHistory(to)), createNavigateResult(
|
|
@@ -854,8 +854,7 @@ const _RouterCore = class _RouterCore extends RouterRegistry {
|
|
|
854
854
|
* @returns {Record<string, any>} - 需要传递给路由视图的props
|
|
855
855
|
*/
|
|
856
856
|
createViewProps(route, name) {
|
|
857
|
-
|
|
858
|
-
const injectProps = (_a = route.injectProps) == null ? void 0 : _a[name];
|
|
857
|
+
const injectProps = route.injectProps?.[name];
|
|
859
858
|
let props;
|
|
860
859
|
return injectProps === !0 ? props = JSON.parse(JSON.stringify(this._currentRouteLocation.params)) : injectProps === !1 ? props = {} : typeof injectProps == "function" ? props = injectProps(this.currentRouteLocation) : isRecordObject(injectProps) ? props = injectProps : props = {}, props;
|
|
861
860
|
}
|
|
@@ -867,8 +866,7 @@ const _RouterCore = class _RouterCore extends RouterRegistry {
|
|
|
867
866
|
* @protected
|
|
868
867
|
*/
|
|
869
868
|
createRouteViewElement(route, name) {
|
|
870
|
-
|
|
871
|
-
const widget = (_a = route.widget) == null ? void 0 : _a[name];
|
|
869
|
+
const widget = route.widget?.[name];
|
|
872
870
|
if (!widget) return;
|
|
873
871
|
const props = this.createViewProps(route, name);
|
|
874
872
|
return props.key = route.path, createElement(widget, props);
|
|
@@ -917,9 +915,8 @@ const _RouterCore = class _RouterCore extends RouterRegistry {
|
|
|
917
915
|
* @return {false | RouteTarget} - 返回false表示阻止导航,返回新的路由目标对象则表示导航到新的目标
|
|
918
916
|
*/
|
|
919
917
|
onBeforeEach(to, from) {
|
|
920
|
-
var _a;
|
|
921
918
|
const matched = to.matched.at(-1);
|
|
922
|
-
return matched && "beforeEnter" in matched && typeof matched.beforeEnter == "function" ? matched.beforeEnter.call(this, to, from) :
|
|
919
|
+
return matched && "beforeEnter" in matched && typeof matched.beforeEnter == "function" ? matched.beforeEnter.call(this, to, from) : this._options.beforeEach?.call(this, to, from);
|
|
923
920
|
}
|
|
924
921
|
/**
|
|
925
922
|
* 触发路由后置守卫
|
|
@@ -928,10 +925,9 @@ const _RouterCore = class _RouterCore extends RouterRegistry {
|
|
|
928
925
|
* @param {ReadonlyRouteLocation} from - 前路由对象
|
|
929
926
|
*/
|
|
930
927
|
onAfterEach(to, from) {
|
|
931
|
-
var _a;
|
|
932
928
|
const matched = to.matched.at(-1);
|
|
933
929
|
if (matched)
|
|
934
|
-
return "afterEnter" in matched && typeof matched.afterEnter == "function" ? matched.afterEnter.call(this, to, from) :
|
|
930
|
+
return "afterEnter" in matched && typeof matched.afterEnter == "function" ? matched.afterEnter.call(this, to, from) : this._options.afterEach?.call(this, to, from);
|
|
935
931
|
}
|
|
936
932
|
/**
|
|
937
933
|
* 更新路由数据
|
|
@@ -996,13 +992,7 @@ const _RouterCore = class _RouterCore extends RouterRegistry {
|
|
|
996
992
|
install(app) {
|
|
997
993
|
app.provide("router", this);
|
|
998
994
|
}
|
|
999
|
-
}
|
|
1000
|
-
/**
|
|
1001
|
-
* 路由器单例实例
|
|
1002
|
-
* 用于全局存储唯一的路由器实例
|
|
1003
|
-
*/
|
|
1004
|
-
__publicField(_RouterCore, "_instance");
|
|
1005
|
-
let RouterCore = _RouterCore;
|
|
995
|
+
}
|
|
1006
996
|
class RouterHistory extends RouterCore {
|
|
1007
997
|
constructor(options) {
|
|
1008
998
|
["path", "hash"].includes(options.mode) || (options.mode = "hash"), super(options), options.mode === "hash" && this.ensureHash();
|
|
@@ -1077,8 +1067,7 @@ class RouterHistory extends RouterCore {
|
|
|
1077
1067
|
* @inheritDoc
|
|
1078
1068
|
*/
|
|
1079
1069
|
replaceHistory(data) {
|
|
1080
|
-
|
|
1081
|
-
const scrollPosition = (_a = this.webHistory.state) == null ? void 0 : _a.scrollPosition;
|
|
1070
|
+
const scrollPosition = this.webHistory.state?.scrollPosition;
|
|
1082
1071
|
this.webHistory.replaceState(this.createState(data), "", data.fullPath), this.completeNavigation(scrollPosition);
|
|
1083
1072
|
}
|
|
1084
1073
|
/**
|
|
@@ -1119,9 +1108,8 @@ class RouterHistory extends RouterCore {
|
|
|
1119
1108
|
* 处理浏览器历史记录的返回/前进事件
|
|
1120
1109
|
*/
|
|
1121
1110
|
onPopState(event) {
|
|
1122
|
-
var _a;
|
|
1123
1111
|
let newTarget;
|
|
1124
|
-
|
|
1112
|
+
event.state?.index ? newTarget = {
|
|
1125
1113
|
index: event.state.index,
|
|
1126
1114
|
hash: event.state.hash,
|
|
1127
1115
|
query: event.state.query
|
|
@@ -1153,16 +1141,15 @@ class RouterHistory extends RouterCore {
|
|
|
1153
1141
|
}
|
|
1154
1142
|
}
|
|
1155
1143
|
class RouterMemory extends RouterCore {
|
|
1144
|
+
// 路由历史记录数组
|
|
1145
|
+
_history = [];
|
|
1146
|
+
// 标记是否有go方法触发的导航
|
|
1147
|
+
_pendingGo = null;
|
|
1156
1148
|
constructor(options) {
|
|
1157
|
-
super(options);
|
|
1158
|
-
// 路由历史记录数组
|
|
1159
|
-
__publicField(this, "_history", []);
|
|
1160
|
-
// 标记是否有go方法触发的导航
|
|
1161
|
-
__publicField(this, "_pendingGo", null);
|
|
1162
|
-
/// 当前历史路由索引
|
|
1163
|
-
__publicField(this, "_currentIndex", 0);
|
|
1164
|
-
options.mode = "memory";
|
|
1149
|
+
super(options), options.mode = "memory";
|
|
1165
1150
|
}
|
|
1151
|
+
/// 当前历史路由索引
|
|
1152
|
+
_currentIndex = 0;
|
|
1166
1153
|
/**
|
|
1167
1154
|
* 当前历史路由索引
|
|
1168
1155
|
*
|
|
@@ -1239,14 +1226,14 @@ function useRoute() {
|
|
|
1239
1226
|
}
|
|
1240
1227
|
const INDEX_SYMBOL = Symbol("RouterViewCounter");
|
|
1241
1228
|
class RouterView extends Widget {
|
|
1229
|
+
// 自身index
|
|
1230
|
+
_$index;
|
|
1231
|
+
// 当前匹配的路由配置
|
|
1232
|
+
_$currentRoute;
|
|
1233
|
+
// 当前视图元素
|
|
1234
|
+
_$currentElement = shallowRef();
|
|
1242
1235
|
constructor(props) {
|
|
1243
1236
|
super(props);
|
|
1244
|
-
// 自身index
|
|
1245
|
-
__publicField(this, "_$index");
|
|
1246
|
-
// 当前匹配的路由配置
|
|
1247
|
-
__publicField(this, "_$currentRoute");
|
|
1248
|
-
// 当前视图元素
|
|
1249
|
-
__publicField(this, "_$currentElement", shallowRef());
|
|
1250
1237
|
const parentIndex = inject(INDEX_SYMBOL, -1);
|
|
1251
1238
|
this._$index = parentIndex + 1, provide(INDEX_SYMBOL, this._$index), this._$currentRoute = this.matchedRoute, this._$currentElement.value = RouterCore.routeViewElement(
|
|
1252
1239
|
this._$currentRoute,
|
|
@@ -1314,8 +1301,7 @@ class RouterView extends Widget {
|
|
|
1314
1301
|
* @protected
|
|
1315
1302
|
*/
|
|
1316
1303
|
get currentWidget() {
|
|
1317
|
-
|
|
1318
|
-
return (_a = this._$currentElement.value) == null ? void 0 : _a.type;
|
|
1304
|
+
return this._$currentElement.value?.type;
|
|
1319
1305
|
}
|
|
1320
1306
|
/**
|
|
1321
1307
|
* 当前的路由位置对象
|
|
@@ -1367,34 +1353,36 @@ class RouterView extends Widget {
|
|
|
1367
1353
|
}
|
|
1368
1354
|
}
|
|
1369
1355
|
class RouterLink extends Widget {
|
|
1356
|
+
/**
|
|
1357
|
+
* 路由目标
|
|
1358
|
+
*
|
|
1359
|
+
* 计算属性
|
|
1360
|
+
*
|
|
1361
|
+
* @protected
|
|
1362
|
+
*/
|
|
1363
|
+
target;
|
|
1364
|
+
/**
|
|
1365
|
+
* 路由目标对应的`RouteLocation`对象
|
|
1366
|
+
*
|
|
1367
|
+
* 计算属性
|
|
1368
|
+
*
|
|
1369
|
+
* @protected
|
|
1370
|
+
*/
|
|
1371
|
+
location;
|
|
1372
|
+
/**
|
|
1373
|
+
* 激活状态
|
|
1374
|
+
*
|
|
1375
|
+
* 计算属性
|
|
1376
|
+
*
|
|
1377
|
+
* @protected
|
|
1378
|
+
*/
|
|
1379
|
+
active = void 0;
|
|
1380
|
+
htmlProps;
|
|
1381
|
+
static isHttpOrHttpsUrl(url) {
|
|
1382
|
+
return /^(https?):\/\/[^\s\/$.?#].\S*$/i.test(url);
|
|
1383
|
+
}
|
|
1370
1384
|
constructor(props) {
|
|
1371
|
-
super(props)
|
|
1372
|
-
/**
|
|
1373
|
-
* 路由目标
|
|
1374
|
-
*
|
|
1375
|
-
* 计算属性
|
|
1376
|
-
*
|
|
1377
|
-
* @protected
|
|
1378
|
-
*/
|
|
1379
|
-
__publicField(this, "target");
|
|
1380
|
-
/**
|
|
1381
|
-
* 路由目标对应的`RouteLocation`对象
|
|
1382
|
-
*
|
|
1383
|
-
* 计算属性
|
|
1384
|
-
*
|
|
1385
|
-
* @protected
|
|
1386
|
-
*/
|
|
1387
|
-
__publicField(this, "location");
|
|
1388
|
-
/**
|
|
1389
|
-
* 激活状态
|
|
1390
|
-
*
|
|
1391
|
-
* 计算属性
|
|
1392
|
-
*
|
|
1393
|
-
* @protected
|
|
1394
|
-
*/
|
|
1395
|
-
__publicField(this, "active");
|
|
1396
|
-
__publicField(this, "htmlProps");
|
|
1397
|
-
this.target = new Computed(() => {
|
|
1385
|
+
super(props), this.target = new Computed(() => {
|
|
1398
1386
|
if (!this.props.to) return;
|
|
1399
1387
|
const to = isString(props.to) ? { index: decodeURIComponent(props.to) } : props.to;
|
|
1400
1388
|
if (RouterLink.isHttpOrHttpsUrl(to.index) || to.index.startsWith("#"))
|
|
@@ -1415,11 +1403,10 @@ class RouterLink extends Widget {
|
|
|
1415
1403
|
) : this.location.value.path === RouterCore.instance.currentRouteLocation.path : !!RouterCore.instance.currentRouteLocation.matched.find(
|
|
1416
1404
|
(route) => route.name === this.target.value.index
|
|
1417
1405
|
))), this.htmlProps = new Computed(() => {
|
|
1418
|
-
var _a;
|
|
1419
1406
|
const props2 = {
|
|
1420
1407
|
href: this.href,
|
|
1421
1408
|
onClick: (e) => this.navigate(e),
|
|
1422
|
-
children: this.children ??
|
|
1409
|
+
children: this.children ?? this.location.value?.index,
|
|
1423
1410
|
draggable: this.props.draggable ?? !1,
|
|
1424
1411
|
"v-bind": [
|
|
1425
1412
|
this.props,
|
|
@@ -1439,15 +1426,11 @@ class RouterLink extends Widget {
|
|
|
1439
1426
|
return this.isActive && (props2["aria-current"] = "page"), this.isDisabled && (props2.disabled = !0), props2;
|
|
1440
1427
|
});
|
|
1441
1428
|
}
|
|
1442
|
-
static isHttpOrHttpsUrl(url) {
|
|
1443
|
-
return /^(https?):\/\/[^\s\/$.?#].\S*$/i.test(url);
|
|
1444
|
-
}
|
|
1445
1429
|
/**
|
|
1446
1430
|
* 当前是否处于激活状态
|
|
1447
1431
|
*/
|
|
1448
1432
|
get isActive() {
|
|
1449
|
-
|
|
1450
|
-
return ((_a = this.active) == null ? void 0 : _a.value) && !this.isDisabled;
|
|
1433
|
+
return this.active?.value && !this.isDisabled;
|
|
1451
1434
|
}
|
|
1452
1435
|
get isDisabled() {
|
|
1453
1436
|
return this.props.disabled ?? !1;
|
|
@@ -1456,8 +1439,7 @@ class RouterLink extends Widget {
|
|
|
1456
1439
|
* 路由目标地址
|
|
1457
1440
|
*/
|
|
1458
1441
|
get href() {
|
|
1459
|
-
|
|
1460
|
-
return typeof this.target.value == "string" ? this.target.value : ((_a = this.location.value) == null ? void 0 : _a.fullPath) || "javascript:void(0)";
|
|
1442
|
+
return typeof this.target.value == "string" ? this.target.value : this.location.value?.fullPath || "javascript:void(0)";
|
|
1461
1443
|
}
|
|
1462
1444
|
/**
|
|
1463
1445
|
* 导航到目标路由
|
|
@@ -1468,9 +1450,8 @@ class RouterLink extends Widget {
|
|
|
1468
1450
|
*/
|
|
1469
1451
|
navigate(e) {
|
|
1470
1452
|
typeof this.target.value != "string" && (e.preventDefault(), this.location.value && !this.isDisabled && RouterCore.instance.navigate(this.location.value).then((res) => {
|
|
1471
|
-
var _a;
|
|
1472
1453
|
res.status !== NavigateStatus.success && console.warn(
|
|
1473
|
-
`[Vitarx.RouterLink][WARN]:导航到索引:${
|
|
1454
|
+
`[Vitarx.RouterLink][WARN]:导航到索引:${this.target.value?.index}失败,${res.message}`
|
|
1474
1455
|
), this.props.callback && this.props.callback(res);
|
|
1475
1456
|
}));
|
|
1476
1457
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var VitarxRouter=(function(exports,vitarx){"use strict";var NavigateStatus=(NavigateStatus2=>(NavigateStatus2[NavigateStatus2.success=0]="success",NavigateStatus2[NavigateStatus2.aborted=1]="aborted",NavigateStatus2[NavigateStatus2.cancelled=2]="cancelled",NavigateStatus2[NavigateStatus2.duplicated=3]="duplicated",NavigateStatus2[NavigateStatus2.not_matched=4]="not_matched",NavigateStatus2[NavigateStatus2.exception=5]="exception",NavigateStatus2))(NavigateStatus||{});function isVariablePath(path){return/\{[^}]+}/.test(path)}function optionalVariableCount(path){const pathWithoutSpaces=path.replace(/\s+/g,""),regex=/\{[\w-]+\?}/g,matches=pathWithoutSpaces.match(regex);return matches?matches.length:0}function isRouteGroup(route){return"children"in route&&route.children!==void 0&&route.children.length>0}function createDynamicPattern(path,pattern,strict,defaultPattern){let optional=0;const processVariable=(varName,isOptional)=>{const regex=pattern[varName];if(regex?regex instanceof RegExp||(console.warn(`[Vitarx.Router][WARN]:${path} 动态路径${varName}变量的自定义正则表达式必须是 RegExp 类型`),pattern[varName]=defaultPattern):pattern[varName]=defaultPattern,isOptional)return optional++,`(?:(${pattern[varName].source}))?`;if(optional)throw new Error(`[Vitarx.Router][ERROR]:动态路径 ${path} 中,可选变量 ${varName} 后不能存在任何必填变量`);return`(${pattern[varName].source})`},processedPath=path.replace(/{([^}?]+)\?}/g,(_,varName)=>processVariable(varName,!0)).replace(/{([^}]+)}/g,(_,varName)=>processVariable(varName,!1)).replace(/\//g,"\\/").replace(/\/?$/,"/?"),flags=strict?"":"i",segments=path.replace(/^\/|\/$/g,"").split("/").length;return{regex:new RegExp(`^${processedPath}$`,flags),length:segments,optional}}function formatPath(path){return path=`/${path}`.replace(/\s+/g,"").replace(/\/+/g,"/"),path.length?path==="/"||path==="/#/"?path:path.replace(/\/$/,""):"/"}function mergePathParams(path,params){if(!isVariablePath(path))return path;const oldPath=path;return path=path.replace(/{([^}]+)\?*}/g,(_match,paramName)=>{const isOptional=paramName.endsWith("?");if(isOptional&&(paramName=paramName.slice(0,-1)),params[paramName]===void 0){if(isOptional)return"";throw new TypeError(`[Vitarx.Router.mergePathParams] 访问路由${oldPath}时缺少参数:${paramName}`)}return String(params[paramName]).replace(/\s+/g,"_")}),formatPath(path)}function formatHash(hash,addHashPrefix){return typeof hash!="string"||!hash?"":(hash=hash.trim(),hash.startsWith("#")?hash:`#${hash}`)}function queryStringToObject(queryString){queryString=decodeURIComponent(queryString);const params=new URLSearchParams(queryString.startsWith("?")?queryString.substring(1):queryString),obj={};return params.forEach((value,key)=>obj[key]=value),obj}function objectToQueryString(obj){const queryString=new URLSearchParams(obj).toString();return queryString?`?${queryString}`:""}function urlToRouteTarget(url,mode,base){let path=decodeURIComponent(url.pathname),hash=decodeURIComponent(url.hash),query=queryStringToObject(url.search);if(path=formatPath(path.startsWith(base)?path.slice(base.length):path),mode==="hash"&&hash.includes("#/")){const hashPart=hash.slice(1),[fullPath,anchor]=hashPart.split("#");path=formatPath(fullPath||"/"),hash=anchor?`#${anchor}`:""}return{index:path,hash,query}}function splitPathAndSuffix(path){const suffix=getPathSuffix(path);return suffix&&(path=path.slice(0,-suffix.length)),{path,suffix:suffix.substring(1)}}function getPathSuffix(path){const lastDotIndex=path.lastIndexOf(".");return lastDotIndex!==-1&&lastDotIndex<path.length-1?`.${path.substring(lastDotIndex+1)}`:""}function isRouteLocationTypeObject(obj){if(typeof obj!="object"||obj===null)return!1;const keys=["index","fullPath","path","hash","params","query","matched","meta"];for(const key of keys)if(!Object.prototype.hasOwnProperty.call(obj,key))return!1;return!0}function validateSuffix(suffix,allowSuffix,inputPath,routePath){return inputPath==="/"||allowSuffix==="*"?!0:allowSuffix===!1?inputPath===routePath:Array.isArray(allowSuffix)?allowSuffix.includes(suffix):suffix===allowSuffix}function addPathSuffix(path,suffix){return suffix&&!path.endsWith("/")&&!path.includes(".")&&(path+=suffix.startsWith(".")?suffix:`.${suffix}`),path}function cloneRouteLocation(route){const{matched,...other}=route;return Object.assign(vitarx.deepClone(other),{matched:Array.from(matched)})}const validInjectProps=props=>["boolean","function"].includes(typeof props);function normalizeInjectProps(route){if(!route.widget)return;const injectProps={},inputValue=route.injectProps??!0,type=typeof inputValue;if(type==="object")for(const name in route.widget){const value=inputValue[name];if(value&&!validInjectProps(value))throw new TypeError(`[Vitarx.Router][ERROR]:请检查 ${route.path} 路由线路配置,injectProps.${name}值错误,仅支持boolean、function类型`);injectProps[name]=value??!0}else if(type==="function"||type==="boolean")for(const name in route.widget)injectProps[name]=inputValue;else throw new TypeError(`[Vitarx.Router][ERROR]:请检查 ${route.path} 路由线路配置,injectProps属性配置错误,仅支持boolean、{key:boolean|function}、function类型`);route.injectProps=injectProps}const validWidgetType=(widget,path)=>{const type=typeof widget;if(type!=="function"){if(type==="object"){if(!widget.default)throw new TypeError(`[Vitarx.Router][ERROR]:请检查 ${path} 路由配置,widget传入对象时则认为是命名视图,命名视图必须具有default视图`);for(const k in widget)validWidgetType(widget[k],path);return}throw new TypeError(`[Vitarx.Router][ERROR]:请检查 ${path} 路由配置,widget配置无效`)}};function normalizeRouteWidget(route){const isGroup=route.children.length;if(route.widget)validWidgetType(route.widget,route.path);else if(!isGroup)throw new TypeError(`[Vitarx.Router][ERROR]:请检查 ${route.path} 路由配置,widget和children不能同时为空。`);typeof route.widget=="function"&&(route.widget={default:route.widget})}function normalizeRoute(route,group,suffix){if(route.meta=route.meta||{},route.pattern=route.pattern||{},route.children=route.children||[],!Array.isArray(route.children))throw new TypeError(`[Vitarx.Router][TYPE_ERROR]:${route.path} 路由线路配置 children 类型错误,它必须是数组类型。`);if(!route.path.trim())throw new TypeError("[Vitarx.Router][TYPE_ERROR]:路由线路配置 path 不能为空");return route.path=formatPath(group?`${group.path}/${route.path}`:route.path),normalizeRouteWidget(route),normalizeInjectProps(route),route.suffix??=group?.suffix??suffix,route.afterEnter??=group?.afterEnter,route.beforeEnter??=group?.beforeEnter,route}class RouterRegistry{_options;_namedRoutes=new Map;_dynamicRoutes=new Map;_pathRoutes=new Map;_parentRoute=new WeakMap;constructor(options){const config={base:"/",strict:!1,mode:"path",scrollBehavior:"auto",anchorsScrollBehavior:"auto",suffix:"*",pattern:/[\w.]+/,defaultSuffix:"",...options};if(config.base=`/${config.base.replace(/^\/+|\/+$/g,"")}`,typeof config.suffix=="string"?config.suffix=config.suffix.replace(/\./g,""):Array.isArray(config.suffix)&&(config.suffix=config.suffix.map(item=>item.replace(/\./g,""))),config.defaultSuffix&&(config.defaultSuffix=config.defaultSuffix.replace(/\./g,"")),config.missing&&typeof config.missing!="function")throw new TypeError("[VitarxRouter][ERROR]:missing配置无效");this._options=config}get options(){return this._options}get mode(){return this._options.mode}get missing(){return this._options.missing}get pathRoutes(){return this._pathRoutes}get namedRoutes(){return this._namedRoutes}get dynamicRoutes(){return this._dynamicRoutes}get routes(){return this._options.routes}get basePath(){return this._options.base}get suffix(){return this._options.suffix}removeRoute(index){const deleteRoute=this.findRoute(index);if(deleteRoute)return this._pathRoutes.delete(deleteRoute.path),deleteRoute.name&&this._namedRoutes.delete(deleteRoute.name),this.removeDynamicRoute(deleteRoute.path),this.removedFromRoutes(deleteRoute),deleteRoute}addRoute(route,parent){if(parent){const parentRoute=this.findRoute(parent);if(!parentRoute)throw new Error(`[Vitarx.Router.addRoute][ERROR]:父路由${parent}不存在`);parentRoute.children.includes(parentRoute)||parentRoute.children.push(this.registerRoute(route,parentRoute))}else this.registerRoute(route),this._options.routes.push(route)}findRoute(target){const isRouterTarget=typeof target=="object",index=isRouterTarget?target.index:target;if(typeof index!="string")throw new TypeError(`[Vitarx.Router.getRoute][ERROR]:路由索引${target}类型错误,必须给定字符串类型`);if(index.startsWith("/")){const matched=this.matchRoute(index);return matched?(matched.params&&isRouterTarget&&(target.params=Object.assign(target.params||{},matched.params)),matched.route):void 0}return this.findNamedRoute(index)}findPathRoute(path){return this._options.strict||(path=path.toLowerCase()),this._pathRoutes.get(path)}findNamedRoute(name){return this._namedRoutes.get(name)}findParentRoute(route){return this._parentRoute.get(route)}matchRoute(path){let formattedPath=formatPath(path);this._options.strict||(formattedPath=formattedPath.toLowerCase());try{const{path:shortPath,suffix}=splitPathAndSuffix(formattedPath),staticRoute=this._pathRoutes.get(shortPath);if(staticRoute&&validateSuffix(suffix,staticRoute.suffix,formattedPath,staticRoute.path))return{route:staticRoute,params:void 0};const segmentCount=shortPath.split("/").filter(Boolean).length,candidates=this._dynamicRoutes.get(segmentCount);if(candidates){const normalizedPath=`${shortPath}/`,regexCache=new Map;for(const{regex,route}of candidates){const match=(regexCache.get(regex.source)||regex).exec(normalizedPath);if(!match)continue;const params={},keys=Object.keys(route.pattern);for(let i=0;i<keys.length;i++)params[keys[i]]=match[i+1];if(validateSuffix(suffix,route.suffix,formattedPath,formattedPath))return{route,params}}}if(!suffix&&!shortPath.endsWith("/index")){const indexRoute=this._pathRoutes.get(`${shortPath==="/"?"":shortPath}/index`);if(indexRoute&&validateSuffix(suffix,indexRoute.suffix,formattedPath,indexRoute.path))return{route:indexRoute,params:void 0}}else if(shortPath==="/index"){const indexRoute=this._pathRoutes.get("/");if(indexRoute&&validateSuffix(suffix,indexRoute.suffix,formattedPath,indexRoute.path))return{route:indexRoute,params:void 0}}}catch(error){console.error("Error in matchRoute:",error);return}}setupRoutes(routes){for(const route of routes)this.registerRoute(route)}removedFromRoutes(route){const parent=this.findParentRoute(route);if(parent?.children){const index2=parent.children.indexOf(route);index2!==-1&&parent.children.splice(index2,1)}const index=this._options.routes.indexOf(route);index!==-1&&this._options.routes.splice(index,1)}removeDynamicRoute(path){if(!isVariablePath(path))return;const length=path.split("/").filter(Boolean).length,removeRouteFromRecords=key=>{const records=this._dynamicRoutes.get(key);if(records){for(let i=0;i<records.length;i++)if(records[i].route.path===path){records.splice(i,1);break}}};removeRouteFromRecords(length);const count=optionalVariableCount(path);if(count>0)for(let i=1;i<=count;i++)removeRouteFromRecords(length-i)}registerRoute(route,group){const normalizedRoute=normalizeRoute(route,group,this.suffix);if(group&&this._parentRoute.set(normalizedRoute,group),isRouteGroup(normalizedRoute)){this.recordRoute(normalizedRoute);for(const child of normalizedRoute.children)this.registerRoute(child,normalizedRoute);normalizedRoute.redirect||(normalizedRoute.redirect=function(to){let first=normalizedRoute.children[0];for(;first;){if(first.redirect)return typeof first.redirect=="function"?first.redirect.call(this,to):first.redirect;if(first.widget)return{index:first.path};first=first.children?.[0]}console.error(`[Vitarx.Router][ERROR]:${normalizedRoute.path} 分组路由在没有配置重定向的情况下,它的第一个子路由必须具有widget或redirect,否则无法匹配视图`,normalizedRoute)})}else this.recordRoute(normalizedRoute);return normalizedRoute}strictPath(path){return this._options.strict?path:path.toLowerCase()}recordRoute(route){if(route.name){if(route.name.startsWith("/")&&(route.name=route.name.replace(/^\//,""),console.warn(`[Vitarx.Router][WARN]:命名路由(name)不要以/开头: ${route.name},因为内部需要使用/区分path、name`)),this._namedRoutes.has(route.name))throw new Error(`[Vitarx.Router][ERROR]:检测到重复的路由名称(name): ${route.name}`);this._namedRoutes.set(route.name,route)}const path=this.strictPath(route.path);if(this._pathRoutes.has(path))throw new Error(`[Vitarx.Router][ERROR]:检测到重复的路由路径(path): ${route.path}`);this._pathRoutes.set(path,route),isVariablePath(route.path)&&this.recordDynamicRoute(route)}recordDynamicRoute(route){const{regex,length,optional}=createDynamicPattern(route.path,route.pattern,this.options.strict,this.options.pattern),addToLengthMap=len=>{this._dynamicRoutes.has(len)||this._dynamicRoutes.set(len,[]),this._dynamicRoutes.get(len).push({regex,route})};if(addToLengthMap(length),optional>0)for(let i=1;i<=optional;i++)addToLengthMap(length-i)}}const __stringValueKeys=["path","hash","index","fullPath"];function patchUpdate(location,newLocation){diffUpdateArrays(location.matched,newLocation.matched),diffUpdateObjects(location.params,newLocation.params),diffUpdateObjects(location.query,newLocation.query),diffUpdateObjects(location.meta,newLocation.meta);for(const key of __stringValueKeys)location[key]!==newLocation[key]&&(location[key]=newLocation[key])}function diffUpdateArrays(a,b){for(let i=0;i<b.length;i++)a[i]!==b[i]&&(a[i]=b[i]);a.length>b.length&&(a.length=b.length)}function diffUpdateObjects(a,b){const aKeys=new Set(Object.keys(a)),bKeys=Object.keys(b);for(const key of bKeys)a[key]=b[key],aKeys.delete(key);for(const key of aKeys)delete a[key]}function diffUpdateProps(oldProps,newProps){const removeKeys=new Set(Object.keys(oldProps)),bKeys=Object.keys(newProps),changes=[];for(const key of bKeys)key!=="key"&&(oldProps[key]!==newProps[key]&&(oldProps[key]=newProps[key],changes.push(key)),removeKeys.delete(key));changes.push(...removeKeys);for(const key of removeKeys)delete oldProps[key];return changes}class RouterCore extends RouterRegistry{_currentTaskId=null;_taskCounter=0;_pendingReplace=null;_pendingPush=null;_scrollBehaviorHandler=void 0;_currentRouteLocation;_readonlyRouteLocation;constructor(options){if(RouterCore._instance)throw new Error("[Vitarx.Router.constructor]:路由器实例已存在,不能创建多个实例");super(options),this._currentRouteLocation=vitarx.reactive({index:this._options.base,path:this._options.base,hash:"",fullPath:"",params:{},query:{},matched:vitarx.shallowReactive([]),meta:vitarx.markRaw({}),suffix:""}),this._readonlyRouteLocation=vitarx.readonly(this._currentRouteLocation)}static _instance;static get instance(){if(!RouterCore._instance)throw new Error("[Vitarx.Router.instance]:路由器实例未初始化");return RouterCore._instance}get initialized(){return RouterCore._instance!==void 0}_isBrowser=typeof window<"u"&&typeof window.document<"u";get isBrowser(){return this._isBrowser}_scrollBehavior="auto";get scrollBehavior(){return this._scrollBehavior}get options(){return this._options}get mode(){return this._options.mode}get currentRouteLocation(){return this._readonlyRouteLocation}get isPendingNavigation(){return!!(this._pendingReplace||this._pendingPush)}get pendingReplaceData(){return this._pendingReplace}get pendingPushData(){return this._pendingPush}static routeViewElement(route,name,index){return route?this.instance.createRouteViewElement(route,name):index===0&&name==="default"&&this.instance.missing&&!this.instance.isPendingNavigation?vitarx.createElement(this.instance.missing):void 0}back(){return this.go(-1)}forward(){return this.go(1)}replace(target){return typeof target=="string"?this.navigate({index:target,isReplace:!0}):(target.isReplace=!0,this.navigate(target))}push(target){return typeof target=="string"?this.navigate({index:target,isReplace:!1}):(target.isReplace=!1,this.navigate(target))}initialize(){return RouterCore._instance?this:(this.setupRoutes(this._options.routes),typeof this.options.scrollBehavior=="function"?this._scrollBehaviorHandler=this.options.scrollBehavior:this._scrollBehavior=this.options.scrollBehavior,this.initializeRouter(),RouterCore._instance=this,this)}scrollTo(scrollTarget){if(!(!this.isBrowser||!scrollTarget||typeof scrollTarget!="object"))try{if("el"in scrollTarget){const{el,...rest}=scrollTarget,element=typeof el=="string"?document.querySelector(el):el;element&&element instanceof Element&&(element.scrollIntoView?element.scrollIntoView({behavior:this.scrollBehavior,...rest}):window.scrollTo({behavior:this.scrollBehavior,top:element.getBoundingClientRect().top+window.scrollY,left:element.getBoundingClientRect().left+window.scrollX}));return}window.scrollTo({behavior:this.scrollBehavior,...scrollTarget})}catch(e){console.error("[Vitarx.Router.scrollTo][WARN]:滚动到指定位置时发生错误,请检查滚动目标参数是否正确",e)}}createRouteLocation(target){if(isRouteLocationTypeObject(target))return target;const route=this.findRoute(target),{index,query={},params={},hash=""}=target,path=route?mergePathParams(route.path,params):formatPath(index),matched=[];if(route){let parent=this.findParentRoute(route);for(;parent;)parent.widget&&matched.unshift(parent),parent=this.findParentRoute(parent);matched.push(route)}const meta=route?.meta?vitarx.deepClone(route.meta):{},hashStr=formatHash(hash),suffix=getPathSuffix(index),fullPath=this.makeFullPath(path,query,hashStr,suffix);return{index,path,hash:hashStr,fullPath,params,query,matched,meta,suffix}}navigate(target){const taskId=++this._taskCounter;this._currentTaskId=taskId;const isCurrentTask=()=>this._currentTaskId===taskId,from=cloneRouteLocation(this.currentRouteLocation),performNavigation=async(_target,isRedirect)=>{const createNavigateResult=(overrides={})=>({from,to,status:NavigateStatus.success,message:"导航成功",redirectFrom:isRedirect?target:void 0,...overrides}),to=this.createRouteLocation(_target);if(to.fullPath===this.currentRouteLocation.fullPath&&vitarx.isDeepEqual(to.params,this.currentRouteLocation.params))return createNavigateResult({status:NavigateStatus.duplicated,message:"导航到相同的路由,被系统阻止!"});if(to.matched.at(-1)===this._currentRouteLocation.matched.at(-1)&&to.path===this._currentRouteLocation.path&&vitarx.isDeepEqual(to.query,this._currentRouteLocation.query)&&to.hash!==this._currentRouteLocation.hash)return this.updateHash(to.hash),createNavigateResult({status:NavigateStatus.success,message:"仅hash变化,导航成功!"});const matched=to.matched.at(-1);if(matched?.redirect){let redirectTarget;if(typeof matched.redirect=="object"&&matched.redirect.index)redirectTarget=matched.redirect;else if(typeof matched.redirect=="string")redirectTarget={index:matched.redirect};else if(typeof matched.redirect=="function"){const redirectHandleResult=matched.redirect.call(this,to);vitarx.isObject(redirectHandleResult)&&(redirectTarget=redirectHandleResult)}if(redirectTarget?.index)return performNavigation(redirectTarget,!0)}try{const result=await this.onBeforeEach(to,from);return result===!1?createNavigateResult({status:NavigateStatus.aborted,message:`导航到${to.index}目标时被前置守卫钩子阻止!`}):isCurrentTask()?typeof result=="object"&&result.index!==_target.index?(result.isReplace??=!1,performNavigation(result,!0)):typeof result=="string"&&result!==_target.index?performNavigation({index:result,isReplace:!1},!0):!to.matched.length&&!this.missing?createNavigateResult({status:NavigateStatus.not_matched,message:`未匹配到任何路由规则,被系统阻止!请检测目标索引(${to.index})是否已注册路由。`}):("isReplace"in _target&&_target.isReplace?(this._pendingReplace=to,this.replaceHistory(to)):(this._pendingPush=to,this.pushHistory(to)),createNavigateResult(!to.matched.length&&this.missing?{status:NavigateStatus.not_matched,message:`${to.fullPath}未匹配到任何路由规则,被系统允许访问,因为系统定义了missing视图。`}:void 0)):createNavigateResult({status:NavigateStatus.cancelled,message:"已被新的导航请求替代,取消此次导航!"})}catch(error){return console.error("[Vitarx.Router.navigate][ERROR]:导航时捕获到了异常",error),createNavigateResult({status:NavigateStatus.exception,message:"导航时捕获到了异常",error})}};return performNavigation(target,!1)}updateQuery(query){vitarx.isDeepEqual(this._currentRouteLocation.query,query)||(this._currentRouteLocation.query=query,this._currentRouteLocation.fullPath=this.makeFullPath(this._currentRouteLocation.path,query,this._currentRouteLocation.hash,this._currentRouteLocation.suffix))}updateHash(hash){if(typeof hash!="string")throw new TypeError(`[Vitarx.Router.updateHash][WARN]:hash值只能是字符串类型,给定${hash}`);const newHash=formatHash(hash);newHash!==this._currentRouteLocation.hash&&(this._currentRouteLocation.hash=newHash,this._currentRouteLocation.fullPath=this.makeFullPath(this._currentRouteLocation.path,this._currentRouteLocation.query,newHash,this._currentRouteLocation.suffix))}createViewProps(route,name){const injectProps=route.injectProps?.[name];let props;return injectProps===!0?props=JSON.parse(JSON.stringify(this._currentRouteLocation.params)):injectProps===!1?props={}:typeof injectProps=="function"?props=injectProps(this.currentRouteLocation):vitarx.isRecordObject(injectProps)?props=injectProps:props={},props}createRouteViewElement(route,name){const widget=route.widget?.[name];if(!widget)return;const props=this.createViewProps(route,name);return props.key=route.path,vitarx.createElement(widget,props)}_completeViewRender(){}completeNavigation(savedPosition){const newData=this.pendingReplaceData||this.pendingPushData;if(!newData)throw new Error("[Vitarx.Router.completeNavigation][ERROR]:没有处于等待状态的导航请求。");const from=cloneRouteLocation(this.currentRouteLocation);this._completeViewRender=()=>{this.onScrollBehavior(this.currentRouteLocation,from,savedPosition).then(),this.onAfterEach(this.currentRouteLocation,from)},this.updateRouteLocation(newData),this._pendingReplace=null,this._pendingPush=null}makeFullPath(path,query,hash,suffix){return hash&&!hash.startsWith("#")&&(hash=`#${hash}`),typeof query=="object"&&(query=objectToQueryString(query)),path=addPathSuffix(path,suffix||this._options.defaultSuffix),this.mode==="hash"?formatPath(`${this.basePath}/${query}#${path}${hash}`):formatPath(`${this.basePath}${path}${query}${hash}`)}onBeforeEach(to,from){const matched=to.matched.at(-1);return matched&&"beforeEnter"in matched&&typeof matched.beforeEnter=="function"?matched.beforeEnter.call(this,to,from):this._options.beforeEach?.call(this,to,from)}onAfterEach(to,from){const matched=to.matched.at(-1);if(matched)return"afterEnter"in matched&&typeof matched.afterEnter=="function"?matched.afterEnter.call(this,to,from):this._options.afterEach?.call(this,to,from)}updateRouteLocation(newLocation){patchUpdate(this._currentRouteLocation,newLocation)}async onScrollBehavior(to,from,savedPosition){try{if(this._scrollBehaviorHandler){const scrollTarget=await this._scrollBehaviorHandler(to,from,savedPosition);scrollTarget&&this.scrollTo(scrollTarget)}else!savedPosition&&!to.hash?this.scrollTo({left:0,top:0}):this.scrollTo(savedPosition??{el:to.hash})}catch(e){console.error("[Vitarx.Router.onScrollBehavior]['ERROR']:处理滚动行为时捕获到了异常",e)}}removeRoute(index){const removed=super.removeRoute(index);if(removed){const index2=this._currentRouteLocation.matched.indexOf(removed);index2!==-1&&this._currentRouteLocation.matched.splice(index2,1)}return removed}install(app){app.provide("router",this)}}class RouterHistory extends RouterCore{constructor(options){["path","hash"].includes(options.mode)||(options.mode="hash"),super(options),options.mode==="hash"&&this.ensureHash()}updateHash(hash){if(super.updateHash(hash),this.saveCurrentScrollPosition(),this.webHistory.pushState(this.createState(this.currentRouteLocation),"",this.currentRouteLocation.fullPath),!hash.trim())window.scrollTo(0,0);else{const anchorId=hash.startsWith("#")?hash.slice(1):hash;try{const element=window.document.getElementById(anchorId);element&&element.scrollIntoView({behavior:this.options.anchorsScrollBehavior})}catch(e){console.error(`滚动到目标锚点${hash}失败`,e)}}}updateQuery(query){super.updateQuery(query),this.webHistory.pushState(this.createState(this.currentRouteLocation),"",this.currentRouteLocation.fullPath)}get currentRouteTarget(){return urlToRouteTarget(window.location,this.mode,this.basePath)}get webHistory(){return window.history}go(delta){this.webHistory.go(delta)}initializeRouter(){window.addEventListener("popstate",this.onPopState.bind(this)),this.replace(this.currentRouteTarget).then(res=>{res.status!==NavigateStatus.success&&console.warn(`[VitarxRouter.initializeRouter]:路由初始化匹配失败,${res.message}`)})}pushHistory(data){this.saveCurrentScrollPosition(),this.webHistory.pushState(this.createState(data),"",data.fullPath),this.completeNavigation()}replaceHistory(data){const scrollPosition=this.webHistory.state?.scrollPosition;this.webHistory.replaceState(this.createState(data),"",data.fullPath),this.completeNavigation(scrollPosition)}saveCurrentScrollPosition(){const scrollPosition={left:window.scrollX,top:window.scrollY,behavior:this.scrollBehavior};this.webHistory.replaceState({...this.webHistory.state,scrollPosition},"",window.location.href)}createState(data,hash,query){const{matched,...state}=data;return typeof hash=="string"&&(state.hash=hash),typeof query=="object"&&(state.query=query),JSON.parse(JSON.stringify(state))}onPopState(event){let newTarget;event.state?.index?newTarget={index:event.state.index,hash:event.state.hash,query:event.state.query}:newTarget=this.currentRouteTarget,this.replace(newTarget).then(res=>{if(!res.redirectFrom&&this.mode==="hash"&&res.status!==NavigateStatus.success)if(res.status===NavigateStatus.not_matched){if(res.to.index.startsWith("/")){const anchorId=res.to.index.slice(1),element=window.document.getElementById(anchorId);element&&element.scrollIntoView({behavior:this.scrollBehavior}),this.updateHash(`#${anchorId}`)}}else res.status===NavigateStatus.duplicated&&this.webHistory.replaceState(this.createState(this.currentRouteLocation),"",this.currentRouteLocation.fullPath)})}ensureHash(){const{pathname,search,hash}=window.location;if(!hash){const path=`${this.basePath}${search}#${pathname}`;window.location.replace(path)}}}class RouterMemory extends RouterCore{_history=[];_pendingGo=null;constructor(options){super(options),options.mode="memory"}_currentIndex=0;get currentIndex(){return this._currentIndex}go(delta){if(!delta)return;const currentIndex=this.currentIndex,targetIndex=Math.max(0,Math.min(this._history.length-1,currentIndex+delta));if(targetIndex===currentIndex)return;const target=this._history[targetIndex];this._pendingGo=targetIndex,this.navigate(target).then(res=>{res.status!==NavigateStatus.success&&(this._pendingGo=null)})}initializeRouter(){this._history.push(this.currentRouteLocation)}pushHistory(data){this._updateHistory(data,!1)}replaceHistory(data){this._updateHistory(data,!0)}_updateHistory(data,isReplace){let newIndex;if(this._pendingGo!==null)this._history[this._pendingGo]=data,newIndex=this._pendingGo;else if(isReplace)this._history[this.currentIndex]=data,newIndex=this.currentIndex;else{const nextIndex=this.currentIndex+1;nextIndex<this._history.length?(this._history[nextIndex]=data,this._history.length=nextIndex+1,newIndex=nextIndex):(this._history.push(data),newIndex=this._history.length-1)}this._currentIndex=newIndex,this.completeNavigation(),this._pendingGo=null}}function defineRoutes(...routes){return routes}function defineRoute(route){return route}function createRouter(options){let router;return typeof window>"u"&&options.mode!=="memory"?(console.warn("当前环境非浏览器端,强制使用内存模式路由"),options.mode="memory",new RouterMemory(options).initialize()):(options.mode==="memory"?router=new RouterMemory(options):router=new RouterHistory(options),router.initialize())}function useRouter(){return RouterCore.instance}function useRoute(){return RouterCore.instance.currentRouteLocation}const INDEX_SYMBOL=Symbol("RouterViewCounter");class RouterView extends vitarx.Widget{_$index;_$currentRoute;_$currentElement=vitarx.shallowRef();constructor(props){super(props);const parentIndex=vitarx.inject(INDEX_SYMBOL,-1);this._$index=parentIndex+1,vitarx.provide(INDEX_SYMBOL,this._$index),this._$currentRoute=this.matchedRoute,this._$currentElement.value=RouterCore.routeViewElement(this._$currentRoute,this.name,this._$index);const router=useRouter();let paramStr=JSON.stringify(this.location.params);vitarx.watch(this.location.matched,(_c,o)=>{const newRoute=o[this.index];newRoute!==this._$currentRoute&&(this._$currentRoute=newRoute,this._$currentElement.value=RouterCore.routeViewElement(newRoute,this.name,this._$index))}),vitarx.watch(this.location.params,()=>{if(!this._$currentRoute)return;const newParams=JSON.stringify(this.location.params);if(newParams!==paramStr){paramStr=newParams;const newProps=router.createViewProps(this._$currentRoute,this.name),oldProps=vitarx.toRaw(this._$currentElement.value.props),changes=diffUpdateProps(oldProps,newProps);changes.length>0&&vitarx.Observer.notify(this._$currentElement.value.props,changes)}})}get index(){return this._$index}get isLastView(){return this.index===this.location.matched.length-1&&this.name==="default"}get name(){return this.props.name||"default"}get matchedRoute(){return this.location.matched[this.index]}get currentElement(){return this._$currentElement.value}get currentWidget(){return this._$currentElement.value?.type}get location(){return RouterCore.instance.currentRouteLocation}onMounted(){this.completeViewRender()}onUpdated(){this.completeViewRender()}build(){return this.currentElement||null}completeViewRender(){this.isLastView&&RouterCore.instance._completeViewRender()}}class RouterLink extends vitarx.Widget{target;location;active=void 0;htmlProps;static isHttpOrHttpsUrl(url){return/^(https?):\/\/[^\s\/$.?#].\S*$/i.test(url)}constructor(props){super(props),this.target=new vitarx.Computed(()=>{if(!this.props.to)return;const to=vitarx.isString(props.to)?{index:decodeURIComponent(props.to)}:props.to;if(RouterLink.isHttpOrHttpsUrl(to.index)||to.index.startsWith("#"))return to.index;if(to.index.includes("#")){const[index,hash]=to.index.split("#",2);to.index=index,to.hash=`#${hash}`}return to}),this.location=new vitarx.Computed(()=>{if(!this.target.value||typeof this.target.value=="string")return;const location=RouterCore.instance.createRouteLocation(this.target.value);return location.matched.length||console.warn(`[Vitarx.RouterLink][WARN]:索引:${this.target.value.index},未匹配到任何有效的路由线路,请检查to属性是否配置正确!`),location}),props.active!==void 0&&props.active!=="none"&&(this.active=new vitarx.Computed(()=>!this.location.value||typeof this.target.value=="string"||!this.target.value?!1:this.target.value.index.startsWith("/")?props.active==="obscure"?this.location.value.path==="/"?RouterCore.instance.currentRouteLocation.path==="/":RouterCore.instance.currentRouteLocation.fullPath.startsWith(this.location.value.path):this.location.value.path===RouterCore.instance.currentRouteLocation.path:!!RouterCore.instance.currentRouteLocation.matched.find(route=>route.name===this.target.value.index))),this.htmlProps=new vitarx.Computed(()=>{const props2={href:this.href,onClick:e=>this.navigate(e),children:this.children??this.location.value?.index,draggable:this.props.draggable??!1,"v-bind":[this.props,["to","children","href","disabled","active","callback","onClick","onclick","aria-current"]]};return this.isActive&&(props2["aria-current"]="page"),this.isDisabled&&(props2.disabled=!0),props2})}get isActive(){return this.active?.value&&!this.isDisabled}get isDisabled(){return this.props.disabled??!1}get href(){return typeof this.target.value=="string"?this.target.value:this.location.value?.fullPath||"javascript:void(0)"}navigate(e){typeof this.target.value!="string"&&(e.preventDefault(),this.location.value&&!this.isDisabled&&RouterCore.instance.navigate(this.location.value).then(res=>{res.status!==NavigateStatus.success&&console.warn(`[Vitarx.RouterLink][WARN]:导航到索引:${this.target.value?.index}失败,${res.message}`),this.props.callback&&this.props.callback(res)}))}build(){return vitarx.createElement("a",this.htmlProps.value)}}return exports.HistoryRouter=RouterHistory,exports.MemoryRouter=RouterMemory,exports.NavigateStatus=NavigateStatus,exports.Router=RouterCore,exports.RouterLink=RouterLink,exports.RouterView=RouterView,exports.createRouter=createRouter,exports.defineRoute=defineRoute,exports.defineRoutes=defineRoutes,exports.useRoute=useRoute,exports.useRouter=useRouter,Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"}),exports})({},Vitarx);
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vitarx-router",
|
|
3
|
-
"version": "3.0.0
|
|
4
|
-
"description": "Vitarx
|
|
3
|
+
"version": "3.0.0",
|
|
4
|
+
"description": "Vitarx前端框架官方路由器",
|
|
5
5
|
"author": "ZhuChongLin <8210856@qq.com>",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"repository": {
|
|
@@ -12,28 +12,21 @@
|
|
|
12
12
|
"keywords": [
|
|
13
13
|
"vitarx",
|
|
14
14
|
"router",
|
|
15
|
-
"vitarx-router"
|
|
16
|
-
"vitarx-router-lib"
|
|
15
|
+
"vitarx-router"
|
|
17
16
|
],
|
|
18
17
|
"type": "module",
|
|
19
|
-
"main": "./dist/vitarx-router.umd.js",
|
|
20
18
|
"module": "./dist/vitarx-router.es.js",
|
|
21
19
|
"types": "./dist/vitarx-router.d.ts",
|
|
22
|
-
"unpkg": "./dist/vitarx-router.
|
|
23
|
-
"jsdelivr": "./dist/vitarx-router.
|
|
20
|
+
"unpkg": "./dist/vitarx-router.iife.js",
|
|
21
|
+
"jsdelivr": "./dist/vitarx-router.iife.js",
|
|
24
22
|
"exports": {
|
|
25
23
|
".": {
|
|
26
|
-
"require": {
|
|
27
|
-
"types": "./dist/vitarx-router.d.ts",
|
|
28
|
-
"node": "./dist/vitarx-router.umd.js"
|
|
29
|
-
},
|
|
30
24
|
"import": {
|
|
31
25
|
"types": "./dist/vitarx-router.d.ts",
|
|
32
|
-
"node": "./index.mjs",
|
|
33
26
|
"default": "./dist/vitarx-router.es.js"
|
|
34
27
|
}
|
|
35
28
|
},
|
|
36
|
-
"./
|
|
29
|
+
"./make": {
|
|
37
30
|
"types": "./dist/scripts/type-make.d.ts",
|
|
38
31
|
"default": "./dist/scripts/type-make.js"
|
|
39
32
|
}
|
|
@@ -42,23 +35,22 @@
|
|
|
42
35
|
"build:script": "tsc --p tsconfig.script.json",
|
|
43
36
|
"build": "rimraf dist && tsc && vite build && npm run build:script",
|
|
44
37
|
"prepublishOnly": "npm run build",
|
|
45
|
-
"push": "npm publish --access=public"
|
|
38
|
+
"push": "npm publish --access=public --registry https://registry.npmjs.org/"
|
|
46
39
|
},
|
|
47
40
|
"peerDependencies": {
|
|
48
|
-
"vitarx": "^3.0.0
|
|
41
|
+
"vitarx": "^3.0.0"
|
|
49
42
|
},
|
|
50
43
|
"devDependencies": {
|
|
51
|
-
"@types/node": "^22.
|
|
52
|
-
"@vitarx/vite-bundler": "3.0.0
|
|
44
|
+
"@types/node": "^22.18.0",
|
|
45
|
+
"@vitarx/vite-bundler": "3.0.0",
|
|
53
46
|
"prettier": "^3.6.2",
|
|
54
47
|
"typescript": "^5.9.2",
|
|
55
|
-
"vite": "^
|
|
48
|
+
"vite": "^7.1.4",
|
|
56
49
|
"vite-plugin-dts": "^4.5.4"
|
|
57
50
|
},
|
|
58
51
|
"files": [
|
|
59
52
|
"dist",
|
|
60
53
|
"LICENSE",
|
|
61
|
-
"README.md"
|
|
62
|
-
"index.mjs"
|
|
54
|
+
"README.md"
|
|
63
55
|
]
|
|
64
56
|
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
(function(global,factory){typeof exports=="object"&&typeof module<"u"?factory(exports,require("vitarx")):typeof define=="function"&&define.amd?define(["exports","vitarx"],factory):(global=typeof globalThis<"u"?globalThis:global||self,factory(global.VitarxRouter={},global.Vitarx))})(this,(function(exports2,vitarx){"use strict";var __defProp=Object.defineProperty;var __defNormalProp=(obj,key,value)=>key in obj?__defProp(obj,key,{enumerable:!0,configurable:!0,writable:!0,value}):obj[key]=value;var __publicField=(obj,key,value)=>__defNormalProp(obj,typeof key!="symbol"?key+"":key,value);var NavigateStatus=(NavigateStatus2=>(NavigateStatus2[NavigateStatus2.success=0]="success",NavigateStatus2[NavigateStatus2.aborted=1]="aborted",NavigateStatus2[NavigateStatus2.cancelled=2]="cancelled",NavigateStatus2[NavigateStatus2.duplicated=3]="duplicated",NavigateStatus2[NavigateStatus2.not_matched=4]="not_matched",NavigateStatus2[NavigateStatus2.exception=5]="exception",NavigateStatus2))(NavigateStatus||{});function isVariablePath(path){return/\{[^}]+}/.test(path)}function optionalVariableCount(path){const pathWithoutSpaces=path.replace(/\s+/g,""),regex=/\{[\w-]+\?}/g,matches=pathWithoutSpaces.match(regex);return matches?matches.length:0}function isRouteGroup(route){return"children"in route&&route.children!==void 0&&route.children.length>0}function createDynamicPattern(path,pattern,strict,defaultPattern){let optional=0;const processVariable=(varName,isOptional)=>{const regex=pattern[varName];if(regex?regex instanceof RegExp||(console.warn(`[Vitarx.Router][WARN]:${path} 动态路径${varName}变量的自定义正则表达式必须是 RegExp 类型`),pattern[varName]=defaultPattern):pattern[varName]=defaultPattern,isOptional)return optional++,`(?:(${pattern[varName].source}))?`;if(optional)throw new Error(`[Vitarx.Router][ERROR]:动态路径 ${path} 中,可选变量 ${varName} 后不能存在任何必填变量`);return`(${pattern[varName].source})`},processedPath=path.replace(/{([^}?]+)\?}/g,(_,varName)=>processVariable(varName,!0)).replace(/{([^}]+)}/g,(_,varName)=>processVariable(varName,!1)).replace(/\//g,"\\/").replace(/\/?$/,"/?"),flags=strict?"":"i",segments=path.replace(/^\/|\/$/g,"").split("/").length;return{regex:new RegExp(`^${processedPath}$`,flags),length:segments,optional}}function formatPath(path){return path=`/${path}`.replace(/\s+/g,"").replace(/\/+/g,"/"),path.length?path==="/"||path==="/#/"?path:path.replace(/\/$/,""):"/"}function mergePathParams(path,params){if(!isVariablePath(path))return path;const oldPath=path;return path=path.replace(/{([^}]+)\?*}/g,(_match,paramName)=>{const isOptional=paramName.endsWith("?");if(isOptional&&(paramName=paramName.slice(0,-1)),params[paramName]===void 0){if(isOptional)return"";throw new TypeError(`[Vitarx.Router.mergePathParams] 访问路由${oldPath}时缺少参数:${paramName}`)}return String(params[paramName]).replace(/\s+/g,"_")}),formatPath(path)}function formatHash(hash,addHashPrefix){return typeof hash!="string"||!hash?"":(hash=hash.trim(),hash.startsWith("#")?hash:`#${hash}`)}function queryStringToObject(queryString){queryString=decodeURIComponent(queryString);const params=new URLSearchParams(queryString.startsWith("?")?queryString.substring(1):queryString),obj={};return params.forEach((value,key)=>obj[key]=value),obj}function objectToQueryString(obj){const queryString=new URLSearchParams(obj).toString();return queryString?`?${queryString}`:""}function urlToRouteTarget(url,mode,base){let path=decodeURIComponent(url.pathname),hash=decodeURIComponent(url.hash),query=queryStringToObject(url.search);if(path=formatPath(path.startsWith(base)?path.slice(base.length):path),mode==="hash"&&hash.includes("#/")){const hashPart=hash.slice(1),[fullPath,anchor]=hashPart.split("#");path=formatPath(fullPath||"/"),hash=anchor?`#${anchor}`:""}return{index:path,hash,query}}function splitPathAndSuffix(path){const suffix=getPathSuffix(path);return suffix&&(path=path.slice(0,-suffix.length)),{path,suffix:suffix.substring(1)}}function getPathSuffix(path){const lastDotIndex=path.lastIndexOf(".");return lastDotIndex!==-1&&lastDotIndex<path.length-1?`.${path.substring(lastDotIndex+1)}`:""}function isRouteLocationTypeObject(obj){if(typeof obj!="object"||obj===null)return!1;const keys=["index","fullPath","path","hash","params","query","matched","meta"];for(const key of keys)if(!Object.prototype.hasOwnProperty.call(obj,key))return!1;return!0}function validateSuffix(suffix,allowSuffix,inputPath,routePath){return inputPath==="/"||allowSuffix==="*"?!0:allowSuffix===!1?inputPath===routePath:Array.isArray(allowSuffix)?allowSuffix.includes(suffix):suffix===allowSuffix}function addPathSuffix(path,suffix){return suffix&&!path.endsWith("/")&&!path.includes(".")&&(path+=suffix.startsWith(".")?suffix:`.${suffix}`),path}function cloneRouteLocation(route){const{matched,...other}=route;return Object.assign(vitarx.deepClone(other),{matched:Array.from(matched)})}const validInjectProps=props=>["boolean","function"].includes(typeof props);function normalizeInjectProps(route){if(!route.widget)return;const injectProps={},inputValue=route.injectProps??!0,type=typeof inputValue;if(type==="object")for(const name in route.widget){const value=inputValue[name];if(value&&!validInjectProps(value))throw new TypeError(`[Vitarx.Router][ERROR]:请检查 ${route.path} 路由线路配置,injectProps.${name}值错误,仅支持boolean、function类型`);injectProps[name]=value??!0}else if(type==="function"||type==="boolean")for(const name in route.widget)injectProps[name]=inputValue;else throw new TypeError(`[Vitarx.Router][ERROR]:请检查 ${route.path} 路由线路配置,injectProps属性配置错误,仅支持boolean、{key:boolean|function}、function类型`);route.injectProps=injectProps}const validWidgetType=(widget,path)=>{const type=typeof widget;if(type!=="function"){if(type==="object"){if(!widget.default)throw new TypeError(`[Vitarx.Router][ERROR]:请检查 ${path} 路由配置,widget传入对象时则认为是命名视图,命名视图必须具有default视图`);for(const k in widget)validWidgetType(widget[k],path);return}throw new TypeError(`[Vitarx.Router][ERROR]:请检查 ${path} 路由配置,widget配置无效`)}};function normalizeRouteWidget(route){const isGroup=route.children.length;if(route.widget)validWidgetType(route.widget,route.path);else if(!isGroup)throw new TypeError(`[Vitarx.Router][ERROR]:请检查 ${route.path} 路由配置,widget和children不能同时为空。`);typeof route.widget=="function"&&(route.widget={default:route.widget})}function normalizeRoute(route,group,suffix){if(route.meta=route.meta||{},route.pattern=route.pattern||{},route.children=route.children||[],!Array.isArray(route.children))throw new TypeError(`[Vitarx.Router][TYPE_ERROR]:${route.path} 路由线路配置 children 类型错误,它必须是数组类型。`);if(!route.path.trim())throw new TypeError("[Vitarx.Router][TYPE_ERROR]:路由线路配置 path 不能为空");return route.path=formatPath(group?`${group.path}/${route.path}`:route.path),normalizeRouteWidget(route),normalizeInjectProps(route),route.suffix??(route.suffix=(group==null?void 0:group.suffix)??suffix),route.afterEnter??(route.afterEnter=group==null?void 0:group.afterEnter),route.beforeEnter??(route.beforeEnter=group==null?void 0:group.beforeEnter),route}class RouterRegistry{constructor(options){__publicField(this,"_options");__publicField(this,"_namedRoutes",new Map);__publicField(this,"_dynamicRoutes",new Map);__publicField(this,"_pathRoutes",new Map);__publicField(this,"_parentRoute",new WeakMap);const config={base:"/",strict:!1,mode:"path",scrollBehavior:"auto",anchorsScrollBehavior:"auto",suffix:"*",pattern:/[\w.]+/,defaultSuffix:"",...options};if(config.base=`/${config.base.replace(/^\/+|\/+$/g,"")}`,typeof config.suffix=="string"?config.suffix=config.suffix.replace(/\./g,""):Array.isArray(config.suffix)&&(config.suffix=config.suffix.map(item=>item.replace(/\./g,""))),config.defaultSuffix&&(config.defaultSuffix=config.defaultSuffix.replace(/\./g,"")),config.missing&&typeof config.missing!="function")throw new TypeError("[VitarxRouter][ERROR]:missing配置无效");this._options=config}get options(){return this._options}get mode(){return this._options.mode}get missing(){return this._options.missing}get pathRoutes(){return this._pathRoutes}get namedRoutes(){return this._namedRoutes}get dynamicRoutes(){return this._dynamicRoutes}get routes(){return this._options.routes}get basePath(){return this._options.base}get suffix(){return this._options.suffix}removeRoute(index){const deleteRoute=this.findRoute(index);if(deleteRoute)return this._pathRoutes.delete(deleteRoute.path),deleteRoute.name&&this._namedRoutes.delete(deleteRoute.name),this.removeDynamicRoute(deleteRoute.path),this.removedFromRoutes(deleteRoute),deleteRoute}addRoute(route,parent){if(parent){const parentRoute=this.findRoute(parent);if(!parentRoute)throw new Error(`[Vitarx.Router.addRoute][ERROR]:父路由${parent}不存在`);parentRoute.children.includes(parentRoute)||parentRoute.children.push(this.registerRoute(route,parentRoute))}else this.registerRoute(route),this._options.routes.push(route)}findRoute(target){const isRouterTarget=typeof target=="object",index=isRouterTarget?target.index:target;if(typeof index!="string")throw new TypeError(`[Vitarx.Router.getRoute][ERROR]:路由索引${target}类型错误,必须给定字符串类型`);if(index.startsWith("/")){const matched=this.matchRoute(index);return matched?(matched.params&&isRouterTarget&&(target.params=Object.assign(target.params||{},matched.params)),matched.route):void 0}return this.findNamedRoute(index)}findPathRoute(path){return this._options.strict||(path=path.toLowerCase()),this._pathRoutes.get(path)}findNamedRoute(name){return this._namedRoutes.get(name)}findParentRoute(route){return this._parentRoute.get(route)}matchRoute(path){let formattedPath=formatPath(path);this._options.strict||(formattedPath=formattedPath.toLowerCase());try{const{path:shortPath,suffix}=splitPathAndSuffix(formattedPath),staticRoute=this._pathRoutes.get(shortPath);if(staticRoute&&validateSuffix(suffix,staticRoute.suffix,formattedPath,staticRoute.path))return{route:staticRoute,params:void 0};const segmentCount=shortPath.split("/").filter(Boolean).length,candidates=this._dynamicRoutes.get(segmentCount);if(candidates){const normalizedPath=`${shortPath}/`,regexCache=new Map;for(const{regex,route}of candidates){const match=(regexCache.get(regex.source)||regex).exec(normalizedPath);if(!match)continue;const params={},keys=Object.keys(route.pattern);for(let i=0;i<keys.length;i++)params[keys[i]]=match[i+1];if(validateSuffix(suffix,route.suffix,formattedPath,formattedPath))return{route,params}}}if(!suffix&&!shortPath.endsWith("/index")){const indexRoute=this._pathRoutes.get(`${shortPath==="/"?"":shortPath}/index`);if(indexRoute&&validateSuffix(suffix,indexRoute.suffix,formattedPath,indexRoute.path))return{route:indexRoute,params:void 0}}else if(shortPath==="/index"){const indexRoute=this._pathRoutes.get("/");if(indexRoute&&validateSuffix(suffix,indexRoute.suffix,formattedPath,indexRoute.path))return{route:indexRoute,params:void 0}}}catch(error){console.error("Error in matchRoute:",error);return}}setupRoutes(routes){for(const route of routes)this.registerRoute(route)}removedFromRoutes(route){const parent=this.findParentRoute(route);if(parent!=null&&parent.children){const index2=parent.children.indexOf(route);index2!==-1&&parent.children.splice(index2,1)}const index=this._options.routes.indexOf(route);index!==-1&&this._options.routes.splice(index,1)}removeDynamicRoute(path){if(!isVariablePath(path))return;const length=path.split("/").filter(Boolean).length,removeRouteFromRecords=key=>{const records=this._dynamicRoutes.get(key);if(records){for(let i=0;i<records.length;i++)if(records[i].route.path===path){records.splice(i,1);break}}};removeRouteFromRecords(length);const count=optionalVariableCount(path);if(count>0)for(let i=1;i<=count;i++)removeRouteFromRecords(length-i)}registerRoute(route,group){const normalizedRoute=normalizeRoute(route,group,this.suffix);if(group&&this._parentRoute.set(normalizedRoute,group),isRouteGroup(normalizedRoute)){this.recordRoute(normalizedRoute);for(const child of normalizedRoute.children)this.registerRoute(child,normalizedRoute);normalizedRoute.redirect||(normalizedRoute.redirect=function(to){var _a;let first=normalizedRoute.children[0];for(;first;){if(first.redirect)return typeof first.redirect=="function"?first.redirect.call(this,to):first.redirect;if(first.widget)return{index:first.path};first=(_a=first.children)==null?void 0:_a[0]}console.error(`[Vitarx.Router][ERROR]:${normalizedRoute.path} 分组路由在没有配置重定向的情况下,它的第一个子路由必须具有widget或redirect,否则无法匹配视图`,normalizedRoute)})}else this.recordRoute(normalizedRoute);return normalizedRoute}strictPath(path){return this._options.strict?path:path.toLowerCase()}recordRoute(route){if(route.name){if(route.name.startsWith("/")&&(route.name=route.name.replace(/^\//,""),console.warn(`[Vitarx.Router][WARN]:命名路由(name)不要以/开头: ${route.name},因为内部需要使用/区分path、name`)),this._namedRoutes.has(route.name))throw new Error(`[Vitarx.Router][ERROR]:检测到重复的路由名称(name): ${route.name}`);this._namedRoutes.set(route.name,route)}const path=this.strictPath(route.path);if(this._pathRoutes.has(path))throw new Error(`[Vitarx.Router][ERROR]:检测到重复的路由路径(path): ${route.path}`);this._pathRoutes.set(path,route),isVariablePath(route.path)&&this.recordDynamicRoute(route)}recordDynamicRoute(route){const{regex,length,optional}=createDynamicPattern(route.path,route.pattern,this.options.strict,this.options.pattern),addToLengthMap=len=>{this._dynamicRoutes.has(len)||this._dynamicRoutes.set(len,[]),this._dynamicRoutes.get(len).push({regex,route})};if(addToLengthMap(length),optional>0)for(let i=1;i<=optional;i++)addToLengthMap(length-i)}}const __stringValueKeys=["path","hash","index","fullPath"];function patchUpdate(location,newLocation){diffUpdateArrays(location.matched,newLocation.matched),diffUpdateObjects(location.params,newLocation.params),diffUpdateObjects(location.query,newLocation.query),diffUpdateObjects(location.meta,newLocation.meta);for(const key of __stringValueKeys)location[key]!==newLocation[key]&&(location[key]=newLocation[key])}function diffUpdateArrays(a,b){for(let i=0;i<b.length;i++)a[i]!==b[i]&&(a[i]=b[i]);a.length>b.length&&(a.length=b.length)}function diffUpdateObjects(a,b){const aKeys=new Set(Object.keys(a)),bKeys=Object.keys(b);for(const key of bKeys)a[key]=b[key],aKeys.delete(key);for(const key of aKeys)delete a[key]}function diffUpdateProps(oldProps,newProps){const removeKeys=new Set(Object.keys(oldProps)),bKeys=Object.keys(newProps),changes=[];for(const key of bKeys)key!=="key"&&(oldProps[key]!==newProps[key]&&(oldProps[key]=newProps[key],changes.push(key)),removeKeys.delete(key));changes.push(...removeKeys);for(const key of removeKeys)delete oldProps[key];return changes}const _RouterCore=class _RouterCore extends RouterRegistry{constructor(options){if(_RouterCore._instance)throw new Error("[Vitarx.Router.constructor]:路由器实例已存在,不能创建多个实例");super(options);__publicField(this,"_currentTaskId",null);__publicField(this,"_taskCounter",0);__publicField(this,"_pendingReplace",null);__publicField(this,"_pendingPush",null);__publicField(this,"_scrollBehaviorHandler");__publicField(this,"_currentRouteLocation");__publicField(this,"_readonlyRouteLocation");__publicField(this,"_isBrowser",typeof window<"u"&&typeof window.document<"u");__publicField(this,"_scrollBehavior","auto");this._currentRouteLocation=vitarx.reactive({index:this._options.base,path:this._options.base,hash:"",fullPath:"",params:{},query:{},matched:vitarx.shallowReactive([]),meta:vitarx.markRaw({}),suffix:""}),this._readonlyRouteLocation=vitarx.readonly(this._currentRouteLocation)}static get instance(){if(!_RouterCore._instance)throw new Error("[Vitarx.Router.instance]:路由器实例未初始化");return _RouterCore._instance}get initialized(){return _RouterCore._instance!==void 0}get isBrowser(){return this._isBrowser}get scrollBehavior(){return this._scrollBehavior}get options(){return this._options}get mode(){return this._options.mode}get currentRouteLocation(){return this._readonlyRouteLocation}get isPendingNavigation(){return!!(this._pendingReplace||this._pendingPush)}get pendingReplaceData(){return this._pendingReplace}get pendingPushData(){return this._pendingPush}static routeViewElement(route,name,index){return route?this.instance.createRouteViewElement(route,name):index===0&&name==="default"&&this.instance.missing&&!this.instance.isPendingNavigation?vitarx.createElement(this.instance.missing):void 0}back(){return this.go(-1)}forward(){return this.go(1)}replace(target){return typeof target=="string"?this.navigate({index:target,isReplace:!0}):(target.isReplace=!0,this.navigate(target))}push(target){return typeof target=="string"?this.navigate({index:target,isReplace:!1}):(target.isReplace=!1,this.navigate(target))}initialize(){return _RouterCore._instance?this:(this.setupRoutes(this._options.routes),typeof this.options.scrollBehavior=="function"?this._scrollBehaviorHandler=this.options.scrollBehavior:this._scrollBehavior=this.options.scrollBehavior,this.initializeRouter(),_RouterCore._instance=this,this)}scrollTo(scrollTarget){if(!(!this.isBrowser||!scrollTarget||typeof scrollTarget!="object"))try{if("el"in scrollTarget){const{el,...rest}=scrollTarget,element=typeof el=="string"?document.querySelector(el):el;element&&element instanceof Element&&(element.scrollIntoView?element.scrollIntoView({behavior:this.scrollBehavior,...rest}):window.scrollTo({behavior:this.scrollBehavior,top:element.getBoundingClientRect().top+window.scrollY,left:element.getBoundingClientRect().left+window.scrollX}));return}window.scrollTo({behavior:this.scrollBehavior,...scrollTarget})}catch(e){console.error("[Vitarx.Router.scrollTo][WARN]:滚动到指定位置时发生错误,请检查滚动目标参数是否正确",e)}}createRouteLocation(target){if(isRouteLocationTypeObject(target))return target;const route=this.findRoute(target),{index,query={},params={},hash=""}=target,path=route?mergePathParams(route.path,params):formatPath(index),matched=[];if(route){let parent=this.findParentRoute(route);for(;parent;)parent.widget&&matched.unshift(parent),parent=this.findParentRoute(parent);matched.push(route)}const meta=route!=null&&route.meta?vitarx.deepClone(route.meta):{},hashStr=formatHash(hash),suffix=getPathSuffix(index),fullPath=this.makeFullPath(path,query,hashStr,suffix);return{index,path,hash:hashStr,fullPath,params,query,matched,meta,suffix}}navigate(target){const taskId=++this._taskCounter;this._currentTaskId=taskId;const isCurrentTask=()=>this._currentTaskId===taskId,from=cloneRouteLocation(this.currentRouteLocation),performNavigation=async(_target,isRedirect)=>{const createNavigateResult=(overrides={})=>({from,to,status:NavigateStatus.success,message:"导航成功",redirectFrom:isRedirect?target:void 0,...overrides}),to=this.createRouteLocation(_target);if(to.fullPath===this.currentRouteLocation.fullPath&&vitarx.isDeepEqual(to.params,this.currentRouteLocation.params))return createNavigateResult({status:NavigateStatus.duplicated,message:"导航到相同的路由,被系统阻止!"});if(to.matched.at(-1)===this._currentRouteLocation.matched.at(-1)&&to.path===this._currentRouteLocation.path&&vitarx.isDeepEqual(to.query,this._currentRouteLocation.query)&&to.hash!==this._currentRouteLocation.hash)return this.updateHash(to.hash),createNavigateResult({status:NavigateStatus.success,message:"仅hash变化,导航成功!"});const matched=to.matched.at(-1);if(matched!=null&&matched.redirect){let redirectTarget;if(typeof matched.redirect=="object"&&matched.redirect.index)redirectTarget=matched.redirect;else if(typeof matched.redirect=="string")redirectTarget={index:matched.redirect};else if(typeof matched.redirect=="function"){const redirectHandleResult=matched.redirect.call(this,to);vitarx.isObject(redirectHandleResult)&&(redirectTarget=redirectHandleResult)}if(redirectTarget!=null&&redirectTarget.index)return performNavigation(redirectTarget,!0)}try{const result=await this.onBeforeEach(to,from);return result===!1?createNavigateResult({status:NavigateStatus.aborted,message:`导航到${to.index}目标时被前置守卫钩子阻止!`}):isCurrentTask()?typeof result=="object"&&result.index!==_target.index?(result.isReplace??(result.isReplace=!1),performNavigation(result,!0)):typeof result=="string"&&result!==_target.index?performNavigation({index:result,isReplace:!1},!0):!to.matched.length&&!this.missing?createNavigateResult({status:NavigateStatus.not_matched,message:`未匹配到任何路由规则,被系统阻止!请检测目标索引(${to.index})是否已注册路由。`}):("isReplace"in _target&&_target.isReplace?(this._pendingReplace=to,this.replaceHistory(to)):(this._pendingPush=to,this.pushHistory(to)),createNavigateResult(!to.matched.length&&this.missing?{status:NavigateStatus.not_matched,message:`${to.fullPath}未匹配到任何路由规则,被系统允许访问,因为系统定义了missing视图。`}:void 0)):createNavigateResult({status:NavigateStatus.cancelled,message:"已被新的导航请求替代,取消此次导航!"})}catch(error){return console.error("[Vitarx.Router.navigate][ERROR]:导航时捕获到了异常",error),createNavigateResult({status:NavigateStatus.exception,message:"导航时捕获到了异常",error})}};return performNavigation(target,!1)}updateQuery(query){vitarx.isDeepEqual(this._currentRouteLocation.query,query)||(this._currentRouteLocation.query=query,this._currentRouteLocation.fullPath=this.makeFullPath(this._currentRouteLocation.path,query,this._currentRouteLocation.hash,this._currentRouteLocation.suffix))}updateHash(hash){if(typeof hash!="string")throw new TypeError(`[Vitarx.Router.updateHash][WARN]:hash值只能是字符串类型,给定${hash}`);const newHash=formatHash(hash);newHash!==this._currentRouteLocation.hash&&(this._currentRouteLocation.hash=newHash,this._currentRouteLocation.fullPath=this.makeFullPath(this._currentRouteLocation.path,this._currentRouteLocation.query,newHash,this._currentRouteLocation.suffix))}createViewProps(route,name){var _a;const injectProps=(_a=route.injectProps)==null?void 0:_a[name];let props;return injectProps===!0?props=JSON.parse(JSON.stringify(this._currentRouteLocation.params)):injectProps===!1?props={}:typeof injectProps=="function"?props=injectProps(this.currentRouteLocation):vitarx.isRecordObject(injectProps)?props=injectProps:props={},props}createRouteViewElement(route,name){var _a;const widget=(_a=route.widget)==null?void 0:_a[name];if(!widget)return;const props=this.createViewProps(route,name);return props.key=route.path,vitarx.createElement(widget,props)}_completeViewRender(){}completeNavigation(savedPosition){const newData=this.pendingReplaceData||this.pendingPushData;if(!newData)throw new Error("[Vitarx.Router.completeNavigation][ERROR]:没有处于等待状态的导航请求。");const from=cloneRouteLocation(this.currentRouteLocation);this._completeViewRender=()=>{this.onScrollBehavior(this.currentRouteLocation,from,savedPosition).then(),this.onAfterEach(this.currentRouteLocation,from)},this.updateRouteLocation(newData),this._pendingReplace=null,this._pendingPush=null}makeFullPath(path,query,hash,suffix){return hash&&!hash.startsWith("#")&&(hash=`#${hash}`),typeof query=="object"&&(query=objectToQueryString(query)),path=addPathSuffix(path,suffix||this._options.defaultSuffix),this.mode==="hash"?formatPath(`${this.basePath}/${query}#${path}${hash}`):formatPath(`${this.basePath}${path}${query}${hash}`)}onBeforeEach(to,from){var _a;const matched=to.matched.at(-1);return matched&&"beforeEnter"in matched&&typeof matched.beforeEnter=="function"?matched.beforeEnter.call(this,to,from):(_a=this._options.beforeEach)==null?void 0:_a.call(this,to,from)}onAfterEach(to,from){var _a;const matched=to.matched.at(-1);if(matched)return"afterEnter"in matched&&typeof matched.afterEnter=="function"?matched.afterEnter.call(this,to,from):(_a=this._options.afterEach)==null?void 0:_a.call(this,to,from)}updateRouteLocation(newLocation){patchUpdate(this._currentRouteLocation,newLocation)}async onScrollBehavior(to,from,savedPosition){try{if(this._scrollBehaviorHandler){const scrollTarget=await this._scrollBehaviorHandler(to,from,savedPosition);scrollTarget&&this.scrollTo(scrollTarget)}else!savedPosition&&!to.hash?this.scrollTo({left:0,top:0}):this.scrollTo(savedPosition??{el:to.hash})}catch(e){console.error("[Vitarx.Router.onScrollBehavior]['ERROR']:处理滚动行为时捕获到了异常",e)}}removeRoute(index){const removed=super.removeRoute(index);if(removed){const index2=this._currentRouteLocation.matched.indexOf(removed);index2!==-1&&this._currentRouteLocation.matched.splice(index2,1)}return removed}install(app){app.provide("router",this)}};__publicField(_RouterCore,"_instance");let RouterCore=_RouterCore;class RouterHistory extends RouterCore{constructor(options){["path","hash"].includes(options.mode)||(options.mode="hash"),super(options),options.mode==="hash"&&this.ensureHash()}updateHash(hash){if(super.updateHash(hash),this.saveCurrentScrollPosition(),this.webHistory.pushState(this.createState(this.currentRouteLocation),"",this.currentRouteLocation.fullPath),!hash.trim())window.scrollTo(0,0);else{const anchorId=hash.startsWith("#")?hash.slice(1):hash;try{const element=window.document.getElementById(anchorId);element&&element.scrollIntoView({behavior:this.options.anchorsScrollBehavior})}catch(e){console.error(`滚动到目标锚点${hash}失败`,e)}}}updateQuery(query){super.updateQuery(query),this.webHistory.pushState(this.createState(this.currentRouteLocation),"",this.currentRouteLocation.fullPath)}get currentRouteTarget(){return urlToRouteTarget(window.location,this.mode,this.basePath)}get webHistory(){return window.history}go(delta){this.webHistory.go(delta)}initializeRouter(){window.addEventListener("popstate",this.onPopState.bind(this)),this.replace(this.currentRouteTarget).then(res=>{res.status!==NavigateStatus.success&&console.warn(`[VitarxRouter.initializeRouter]:路由初始化匹配失败,${res.message}`)})}pushHistory(data){this.saveCurrentScrollPosition(),this.webHistory.pushState(this.createState(data),"",data.fullPath),this.completeNavigation()}replaceHistory(data){var _a;const scrollPosition=(_a=this.webHistory.state)==null?void 0:_a.scrollPosition;this.webHistory.replaceState(this.createState(data),"",data.fullPath),this.completeNavigation(scrollPosition)}saveCurrentScrollPosition(){const scrollPosition={left:window.scrollX,top:window.scrollY,behavior:this.scrollBehavior};this.webHistory.replaceState({...this.webHistory.state,scrollPosition},"",window.location.href)}createState(data,hash,query){const{matched,...state}=data;return typeof hash=="string"&&(state.hash=hash),typeof query=="object"&&(state.query=query),JSON.parse(JSON.stringify(state))}onPopState(event){var _a;let newTarget;(_a=event.state)!=null&&_a.index?newTarget={index:event.state.index,hash:event.state.hash,query:event.state.query}:newTarget=this.currentRouteTarget,this.replace(newTarget).then(res=>{if(!res.redirectFrom&&this.mode==="hash"&&res.status!==NavigateStatus.success)if(res.status===NavigateStatus.not_matched){if(res.to.index.startsWith("/")){const anchorId=res.to.index.slice(1),element=window.document.getElementById(anchorId);element&&element.scrollIntoView({behavior:this.scrollBehavior}),this.updateHash(`#${anchorId}`)}}else res.status===NavigateStatus.duplicated&&this.webHistory.replaceState(this.createState(this.currentRouteLocation),"",this.currentRouteLocation.fullPath)})}ensureHash(){const{pathname,search,hash}=window.location;if(!hash){const path=`${this.basePath}${search}#${pathname}`;window.location.replace(path)}}}class RouterMemory extends RouterCore{constructor(options){super(options);__publicField(this,"_history",[]);__publicField(this,"_pendingGo",null);__publicField(this,"_currentIndex",0);options.mode="memory"}get currentIndex(){return this._currentIndex}go(delta){if(!delta)return;const currentIndex=this.currentIndex,targetIndex=Math.max(0,Math.min(this._history.length-1,currentIndex+delta));if(targetIndex===currentIndex)return;const target=this._history[targetIndex];this._pendingGo=targetIndex,this.navigate(target).then(res=>{res.status!==NavigateStatus.success&&(this._pendingGo=null)})}initializeRouter(){this._history.push(this.currentRouteLocation)}pushHistory(data){this._updateHistory(data,!1)}replaceHistory(data){this._updateHistory(data,!0)}_updateHistory(data,isReplace){let newIndex;if(this._pendingGo!==null)this._history[this._pendingGo]=data,newIndex=this._pendingGo;else if(isReplace)this._history[this.currentIndex]=data,newIndex=this.currentIndex;else{const nextIndex=this.currentIndex+1;nextIndex<this._history.length?(this._history[nextIndex]=data,this._history.length=nextIndex+1,newIndex=nextIndex):(this._history.push(data),newIndex=this._history.length-1)}this._currentIndex=newIndex,this.completeNavigation(),this._pendingGo=null}}function defineRoutes(...routes){return routes}function defineRoute(route){return route}function createRouter(options){let router;return typeof window>"u"&&options.mode!=="memory"?(console.warn("当前环境非浏览器端,强制使用内存模式路由"),options.mode="memory",new RouterMemory(options).initialize()):(options.mode==="memory"?router=new RouterMemory(options):router=new RouterHistory(options),router.initialize())}function useRouter(){return RouterCore.instance}function useRoute(){return RouterCore.instance.currentRouteLocation}const INDEX_SYMBOL=Symbol("RouterViewCounter");class RouterView extends vitarx.Widget{constructor(props){super(props);__publicField(this,"_$index");__publicField(this,"_$currentRoute");__publicField(this,"_$currentElement",vitarx.shallowRef());const parentIndex=vitarx.inject(INDEX_SYMBOL,-1);this._$index=parentIndex+1,vitarx.provide(INDEX_SYMBOL,this._$index),this._$currentRoute=this.matchedRoute,this._$currentElement.value=RouterCore.routeViewElement(this._$currentRoute,this.name,this._$index);const router=useRouter();let paramStr=JSON.stringify(this.location.params);vitarx.watch(this.location.matched,(_c,o)=>{const newRoute=o[this.index];newRoute!==this._$currentRoute&&(this._$currentRoute=newRoute,this._$currentElement.value=RouterCore.routeViewElement(newRoute,this.name,this._$index))}),vitarx.watch(this.location.params,()=>{if(!this._$currentRoute)return;const newParams=JSON.stringify(this.location.params);if(newParams!==paramStr){paramStr=newParams;const newProps=router.createViewProps(this._$currentRoute,this.name),oldProps=vitarx.toRaw(this._$currentElement.value.props),changes=diffUpdateProps(oldProps,newProps);changes.length>0&&vitarx.Observer.notify(this._$currentElement.value.props,changes)}})}get index(){return this._$index}get isLastView(){return this.index===this.location.matched.length-1&&this.name==="default"}get name(){return this.props.name||"default"}get matchedRoute(){return this.location.matched[this.index]}get currentElement(){return this._$currentElement.value}get currentWidget(){var _a;return(_a=this._$currentElement.value)==null?void 0:_a.type}get location(){return RouterCore.instance.currentRouteLocation}onMounted(){this.completeViewRender()}onUpdated(){this.completeViewRender()}build(){return this.currentElement||null}completeViewRender(){this.isLastView&&RouterCore.instance._completeViewRender()}}class RouterLink extends vitarx.Widget{constructor(props){super(props);__publicField(this,"target");__publicField(this,"location");__publicField(this,"active");__publicField(this,"htmlProps");this.target=new vitarx.Computed(()=>{if(!this.props.to)return;const to=vitarx.isString(props.to)?{index:decodeURIComponent(props.to)}:props.to;if(RouterLink.isHttpOrHttpsUrl(to.index)||to.index.startsWith("#"))return to.index;if(to.index.includes("#")){const[index,hash]=to.index.split("#",2);to.index=index,to.hash=`#${hash}`}return to}),this.location=new vitarx.Computed(()=>{if(!this.target.value||typeof this.target.value=="string")return;const location=RouterCore.instance.createRouteLocation(this.target.value);return location.matched.length||console.warn(`[Vitarx.RouterLink][WARN]:索引:${this.target.value.index},未匹配到任何有效的路由线路,请检查to属性是否配置正确!`),location}),props.active!==void 0&&props.active!=="none"&&(this.active=new vitarx.Computed(()=>!this.location.value||typeof this.target.value=="string"||!this.target.value?!1:this.target.value.index.startsWith("/")?props.active==="obscure"?this.location.value.path==="/"?RouterCore.instance.currentRouteLocation.path==="/":RouterCore.instance.currentRouteLocation.fullPath.startsWith(this.location.value.path):this.location.value.path===RouterCore.instance.currentRouteLocation.path:!!RouterCore.instance.currentRouteLocation.matched.find(route=>route.name===this.target.value.index))),this.htmlProps=new vitarx.Computed(()=>{var _a;const props2={href:this.href,onClick:e=>this.navigate(e),children:this.children??((_a=this.location.value)==null?void 0:_a.index),draggable:this.props.draggable??!1,"v-bind":[this.props,["to","children","href","disabled","active","callback","onClick","onclick","aria-current"]]};return this.isActive&&(props2["aria-current"]="page"),this.isDisabled&&(props2.disabled=!0),props2})}static isHttpOrHttpsUrl(url){return/^(https?):\/\/[^\s\/$.?#].\S*$/i.test(url)}get isActive(){var _a;return((_a=this.active)==null?void 0:_a.value)&&!this.isDisabled}get isDisabled(){return this.props.disabled??!1}get href(){var _a;return typeof this.target.value=="string"?this.target.value:((_a=this.location.value)==null?void 0:_a.fullPath)||"javascript:void(0)"}navigate(e){typeof this.target.value!="string"&&(e.preventDefault(),this.location.value&&!this.isDisabled&&RouterCore.instance.navigate(this.location.value).then(res=>{var _a;res.status!==NavigateStatus.success&&console.warn(`[Vitarx.RouterLink][WARN]:导航到索引:${(_a=this.target.value)==null?void 0:_a.index}失败,${res.message}`),this.props.callback&&this.props.callback(res)}))}build(){return vitarx.createElement("a",this.htmlProps.value)}}exports2.HistoryRouter=RouterHistory,exports2.MemoryRouter=RouterMemory,exports2.NavigateStatus=NavigateStatus,exports2.Router=RouterCore,exports2.RouterLink=RouterLink,exports2.RouterView=RouterView,exports2.createRouter=createRouter,exports2.defineRoute=defineRoute,exports2.defineRoutes=defineRoutes,exports2.useRoute=useRoute,exports2.useRouter=useRouter,Object.defineProperty(exports2,Symbol.toStringTag,{value:"Module"})}));
|
package/index.mjs
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export * from './dist/vitarx-router.es.js'
|