vitarx-router 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +14 -0
- package/dist/index.d.ts +2 -0
- package/dist/router/helper.d.ts +92 -0
- package/dist/router/index.d.ts +6 -0
- package/dist/router/memory-router.d.ts +45 -0
- package/dist/router/router.d.ts +414 -0
- package/dist/router/type.d.ts +477 -0
- package/dist/router/update.d.ts +8 -0
- package/dist/router/utils.d.ts +152 -0
- package/dist/router/validate/index.d.ts +2 -0
- package/dist/router/validate/inject-props.d.ts +8 -0
- package/dist/router/validate/validate-widget.d.ts +8 -0
- package/dist/router/web-history-router.d.ts +65 -0
- package/dist/vitarx-router.js +1223 -0
- package/dist/widget/RouterView.d.ts +84 -0
- package/dist/widget/index.d.ts +1 -0
- package/package.json +30 -0
|
@@ -0,0 +1,1223 @@
|
|
|
1
|
+
var D = Object.defineProperty;
|
|
2
|
+
var j = (e) => {
|
|
3
|
+
throw TypeError(e);
|
|
4
|
+
};
|
|
5
|
+
var M = (e, t, i) => t in e ? D(e, t, { enumerable: !0, configurable: !0, writable: !0, value: i }) : e[t] = i;
|
|
6
|
+
var l = (e, t, i) => M(e, typeof t != "symbol" ? t + "" : t, i), B = (e, t, i) => t.has(e) || j("Cannot " + i);
|
|
7
|
+
var f = (e, t, i) => (B(e, t, "read from private field"), i ? i.call(e) : t.get(e)), x = (e, t, i) => t.has(e) ? j("Cannot add the same private member more than once") : t instanceof WeakSet ? t.add(e) : t.set(e, i), v = (e, t, i, n) => (B(e, t, "write to private field"), n ? n.call(e, i) : t.set(e, i), i);
|
|
8
|
+
import { reactive as U, shallowReactive as G, createElement as V, LazyWidget as q, deepEqual as k, deepClone as K, Widget as J, shallowRef as Q, inject as X, provide as Z, watch as N, Fragment as tt } from "vitarx";
|
|
9
|
+
var g = /* @__PURE__ */ ((e) => (e[e.success = 0] = "success", e[e.aborted = 1] = "aborted", e[e.cancelled = 2] = "cancelled", e[e.duplicated = 3] = "duplicated", e[e.not_matched = 4] = "not_matched", e[e.exception = 5] = "exception", e))(g || {});
|
|
10
|
+
function T(e) {
|
|
11
|
+
return typeof e == "boolean" || typeof e == "function" || typeof e == "object" && e !== null;
|
|
12
|
+
}
|
|
13
|
+
function et(e) {
|
|
14
|
+
if (e.widget === void 0) return;
|
|
15
|
+
if (!("injectProps" in e)) {
|
|
16
|
+
e.injectProps = I(e, !0);
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
const t = e.injectProps;
|
|
20
|
+
if (typeof t == "object")
|
|
21
|
+
it(t) ? nt(e, t) : st(e, t);
|
|
22
|
+
else if (T(t))
|
|
23
|
+
e.injectProps = I(e, t);
|
|
24
|
+
else
|
|
25
|
+
throw new TypeError(
|
|
26
|
+
`[Vitarx.Router][TYPE_ERROR]:${e.path} 路由线路配置的 injectProps 类型有误,它可以是布尔值、函数,亦或是一个{string:any}类型的对象。`
|
|
27
|
+
);
|
|
28
|
+
}
|
|
29
|
+
function it(e) {
|
|
30
|
+
return Object.keys(e).length === 1 && "default" in e;
|
|
31
|
+
}
|
|
32
|
+
function nt(e, t) {
|
|
33
|
+
if (!T(t.default))
|
|
34
|
+
throw new TypeError(
|
|
35
|
+
`[Vitarx.Router][TYPE_ERROR]:${e.path} 路由线路配置的 injectProps.default 类型有误,它可以是布尔值、函数,亦或是一个{string:any}类型的对象。`
|
|
36
|
+
);
|
|
37
|
+
}
|
|
38
|
+
function st(e, t) {
|
|
39
|
+
for (const i of Object.keys(e.widget))
|
|
40
|
+
if (i in t) {
|
|
41
|
+
if (!T(t[i]))
|
|
42
|
+
throw new TypeError(
|
|
43
|
+
`[Vitarx.Router][TYPE_ERROR]:${e.path} 路由线路配置的 injectProps.${i} 类型有误,它可以是布尔值、函数,亦或是一个{string:any}类型的对象。`
|
|
44
|
+
);
|
|
45
|
+
} else
|
|
46
|
+
t[i] = !0;
|
|
47
|
+
}
|
|
48
|
+
function I(e, t) {
|
|
49
|
+
const i = {};
|
|
50
|
+
for (const n of Object.keys(e.widget))
|
|
51
|
+
i[n] = t;
|
|
52
|
+
return i;
|
|
53
|
+
}
|
|
54
|
+
function rt(e) {
|
|
55
|
+
if (!("widget" in e)) {
|
|
56
|
+
if (e.children.length === 0)
|
|
57
|
+
throw new TypeError(
|
|
58
|
+
`[Vitarx.Router][TYPE_ERROR]:${e.path} 路由线路配置的 widget 属性缺失,它可以是函数式小部件、类小部件,亦或是一个惰性加载器。`
|
|
59
|
+
);
|
|
60
|
+
e.widget = void 0;
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
if (typeof e.widget == "function")
|
|
64
|
+
e.widget = { default: e.widget };
|
|
65
|
+
else if (typeof e.widget == "object" && e.widget !== null) {
|
|
66
|
+
if (Object.keys(e.widget).length === 0)
|
|
67
|
+
e.widget = void 0;
|
|
68
|
+
else
|
|
69
|
+
for (const t in e.widget)
|
|
70
|
+
if (typeof e.widget[t] != "function")
|
|
71
|
+
throw new TypeError(
|
|
72
|
+
`[Vitarx.Router][TYPE_ERROR]:${e.path} 路由线路配置的 widget 命名视图 ${t} 类型有误,它可以是函数式小部件、类小部件,亦或是一个惰性加载器。`
|
|
73
|
+
);
|
|
74
|
+
} else
|
|
75
|
+
throw new TypeError(
|
|
76
|
+
`[Vitarx.Router][TYPE_ERROR]:${e.path} 路由线路配置的 widget 类型有误,它可以是函数式小部件、类小部件,亦或是一个惰性加载器。`
|
|
77
|
+
);
|
|
78
|
+
}
|
|
79
|
+
const F = Symbol("LazyLoader");
|
|
80
|
+
function O(e) {
|
|
81
|
+
return /\{[^}]+}/.test(e);
|
|
82
|
+
}
|
|
83
|
+
function ot(e) {
|
|
84
|
+
const t = e.replace(/\s+/g, ""), i = /\{[\w-]+\?}/g, n = t.match(i);
|
|
85
|
+
return n ? n.length : 0;
|
|
86
|
+
}
|
|
87
|
+
function H(e) {
|
|
88
|
+
return "children" in e && e.children !== void 0 && e.children.length > 0;
|
|
89
|
+
}
|
|
90
|
+
function ct(e, t, i, n) {
|
|
91
|
+
let s = 0;
|
|
92
|
+
const r = (h, c) => {
|
|
93
|
+
const _ = t[h];
|
|
94
|
+
if (_ ? _ instanceof RegExp || (console.warn(
|
|
95
|
+
`[Vitarx.Router][WARN]:${e} 动态路径${h}变量的自定义正则表达式必须是 RegExp 类型`
|
|
96
|
+
), t[h] = n) : t[h] = n, c)
|
|
97
|
+
return s++, `(?:(${t[h].source}))?`;
|
|
98
|
+
if (s)
|
|
99
|
+
throw new Error(
|
|
100
|
+
`[Vitarx.Router][ERROR]:动态路径 ${e} 中,可选变量 ${h} 后不能存在任何必填变量`
|
|
101
|
+
);
|
|
102
|
+
return `(${t[h].source})`;
|
|
103
|
+
}, o = e.replace(/{([^}?]+)\?}/g, (h, c) => r(c, !0)).replace(/{([^}]+)}/g, (h, c) => r(c, !1)).replace(/\//g, "\\/").replace(/\/?$/, "/?"), u = i ? "" : "i", a = e.replace(/^\/|\/$/g, "").split("/").length;
|
|
104
|
+
return {
|
|
105
|
+
regex: new RegExp(`^${o}$`, u),
|
|
106
|
+
length: a,
|
|
107
|
+
optional: s
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
function d(e) {
|
|
111
|
+
return e = e.replace(/\s+/g, "").replace(/\/+/g, "/"), e.length ? e === "/" || e === "/#/" ? e : e.replace(/\/$/, "") : "/";
|
|
112
|
+
}
|
|
113
|
+
function S(e, t) {
|
|
114
|
+
if (!O(e)) return e;
|
|
115
|
+
const i = e;
|
|
116
|
+
return e = e.replace(/{([^}]+)\?*}/g, (n, s) => {
|
|
117
|
+
const r = s.endsWith("?");
|
|
118
|
+
if (r && (s = s.slice(0, -1)), t[s] === void 0) {
|
|
119
|
+
if (r) return "";
|
|
120
|
+
throw new TypeError(
|
|
121
|
+
`[Vitarx.Router.mergePathParams] 访问路由${i}时缺少参数:${s}`
|
|
122
|
+
);
|
|
123
|
+
}
|
|
124
|
+
return String(t[s]).replace(/\s+/g, "_");
|
|
125
|
+
}), d(e);
|
|
126
|
+
}
|
|
127
|
+
function at(e) {
|
|
128
|
+
return typeof e == "function" && e[F];
|
|
129
|
+
}
|
|
130
|
+
function W(e, t) {
|
|
131
|
+
return typeof e != "string" || !e ? "" : (e = e.trim(), e.startsWith("#") ? e : `#${e}`);
|
|
132
|
+
}
|
|
133
|
+
function L(e) {
|
|
134
|
+
e = decodeURIComponent(e);
|
|
135
|
+
const t = new URLSearchParams(
|
|
136
|
+
e.startsWith("?") ? e.substring(1) : e
|
|
137
|
+
), i = {};
|
|
138
|
+
return t.forEach((n, s) => i[s] = n), i;
|
|
139
|
+
}
|
|
140
|
+
function ht(e) {
|
|
141
|
+
const t = new URLSearchParams(e).toString();
|
|
142
|
+
return t ? `?${t}` : "";
|
|
143
|
+
}
|
|
144
|
+
function ut(e, t, i) {
|
|
145
|
+
let n = decodeURIComponent(e.pathname), s = decodeURIComponent(e.hash), r;
|
|
146
|
+
if (t === "path")
|
|
147
|
+
return r = L(e.search), n.startsWith(i) ? n = d(n.slice(i.length)) : n = d(n), { index: n, hash: s, query: r };
|
|
148
|
+
if (s.includes("#")) {
|
|
149
|
+
const o = s.slice(1), [u, a] = o.split("#"), [h, c] = u.split("?");
|
|
150
|
+
n = d(h || ""), s = a ? `#${a}` : "", r = L(c || "");
|
|
151
|
+
} else
|
|
152
|
+
n = i, r = L(e.search);
|
|
153
|
+
return { index: n, hash: s, query: r };
|
|
154
|
+
}
|
|
155
|
+
function lt(e) {
|
|
156
|
+
const t = Y(e);
|
|
157
|
+
return t && (e = e.slice(0, -t.length)), {
|
|
158
|
+
path: e,
|
|
159
|
+
suffix: t
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
function Y(e) {
|
|
163
|
+
const t = e.match(/^(.*?)(\.[a-zA-Z0-9]+)$/);
|
|
164
|
+
return t ? t[2] : "";
|
|
165
|
+
}
|
|
166
|
+
function ft(e) {
|
|
167
|
+
if (typeof e != "object" || e === null) return !1;
|
|
168
|
+
const t = [
|
|
169
|
+
"index",
|
|
170
|
+
"fullPath",
|
|
171
|
+
"path",
|
|
172
|
+
"hash",
|
|
173
|
+
"params",
|
|
174
|
+
"query",
|
|
175
|
+
"matched"
|
|
176
|
+
];
|
|
177
|
+
for (const i of t)
|
|
178
|
+
if (!Object.prototype.hasOwnProperty.call(e, i)) return !1;
|
|
179
|
+
return !0;
|
|
180
|
+
}
|
|
181
|
+
function dt(e) {
|
|
182
|
+
if (e.meta = e.meta || {}, e.pattern = e.pattern || {}, e.children = e.children || [], !Array.isArray(e.children))
|
|
183
|
+
throw new TypeError(
|
|
184
|
+
`[Vitarx.Router][TYPE_ERROR]:${e.path} 路由线路配置 children 类型错误,它必须是数组类型。`
|
|
185
|
+
);
|
|
186
|
+
if (!e.path.trim())
|
|
187
|
+
throw new TypeError("[Vitarx.Router][TYPE_ERROR]:路由线路配置 path 不能为空");
|
|
188
|
+
return e.path = d(e.path), rt(e), et(e), e;
|
|
189
|
+
}
|
|
190
|
+
const pt = ["path", "hash", "index", "fullPath"];
|
|
191
|
+
function Rt(e, t) {
|
|
192
|
+
gt(e.matched, t.matched), A(e.params, t.params), A(e.query, t.query);
|
|
193
|
+
for (const i of pt)
|
|
194
|
+
e[i] !== t[i] && (e[i] = t[i]);
|
|
195
|
+
}
|
|
196
|
+
function gt(e, t) {
|
|
197
|
+
for (let i = 0; i < t.length; i++)
|
|
198
|
+
e[i] !== t[i] && (e[i] = t[i]);
|
|
199
|
+
e.length > t.length && (e.length = t.length);
|
|
200
|
+
}
|
|
201
|
+
function A(e, t) {
|
|
202
|
+
const i = Object.keys(e), n = Object.keys(t);
|
|
203
|
+
for (const s of n)
|
|
204
|
+
t.hasOwnProperty(s) && (e[s] = t[s]);
|
|
205
|
+
for (const s in i)
|
|
206
|
+
s in t || delete e[s];
|
|
207
|
+
}
|
|
208
|
+
var m;
|
|
209
|
+
const R = class R {
|
|
210
|
+
constructor(t) {
|
|
211
|
+
// 配置
|
|
212
|
+
l(this, "_options");
|
|
213
|
+
// 命名路由映射
|
|
214
|
+
l(this, "_namedRoutes", /* @__PURE__ */ new Map());
|
|
215
|
+
// 动态路由正则,按长度分组
|
|
216
|
+
l(this, "_dynamicRoutes", /* @__PURE__ */ new Map());
|
|
217
|
+
// 路由path映射
|
|
218
|
+
l(this, "_pathRoutes", /* @__PURE__ */ new Map());
|
|
219
|
+
// 父路由映射
|
|
220
|
+
l(this, "_parentRoute", /* @__PURE__ */ new WeakMap());
|
|
221
|
+
// 当前任务 ID
|
|
222
|
+
l(this, "_currentTaskId", null);
|
|
223
|
+
// 用于生成唯一任务 ID
|
|
224
|
+
l(this, "_taskCounter", 0);
|
|
225
|
+
/**
|
|
226
|
+
* 是否正在执行 replace 操作
|
|
227
|
+
*
|
|
228
|
+
* @private
|
|
229
|
+
*/
|
|
230
|
+
l(this, "_pendingReplace", null);
|
|
231
|
+
/**
|
|
232
|
+
* 是否正在执行 push 操作
|
|
233
|
+
*
|
|
234
|
+
* @private
|
|
235
|
+
*/
|
|
236
|
+
l(this, "_pendingPush", null);
|
|
237
|
+
// 滚动行为处理器
|
|
238
|
+
l(this, "_scrollBehaviorHandler");
|
|
239
|
+
// 当前路由数据
|
|
240
|
+
l(this, "_currentRouteLocation");
|
|
241
|
+
// 是否运行在浏览器端
|
|
242
|
+
l(this, "_isBrowser", typeof window < "u" && typeof window.document < "u");
|
|
243
|
+
// 滚动行为
|
|
244
|
+
l(this, "_scrollBehavior", "auto");
|
|
245
|
+
if (f(R, m))
|
|
246
|
+
throw new Error("[Vitarx.Router.constructor]:路由器实例已存在,不能创建多个实例");
|
|
247
|
+
this._options = {
|
|
248
|
+
base: "/",
|
|
249
|
+
strict: !1,
|
|
250
|
+
mode: "path",
|
|
251
|
+
scrollBehavior: "smooth",
|
|
252
|
+
suffix: !1,
|
|
253
|
+
pattern: /[\w.]+/,
|
|
254
|
+
...t
|
|
255
|
+
}, this._options.base = `/${this._options.base.replace(/^\/+|\/+$/g, "")}`, this._currentRouteLocation = U({
|
|
256
|
+
index: this._options.base,
|
|
257
|
+
path: this._options.base,
|
|
258
|
+
hash: "",
|
|
259
|
+
fullPath: this._options.base,
|
|
260
|
+
params: {},
|
|
261
|
+
query: {},
|
|
262
|
+
matched: G([])
|
|
263
|
+
});
|
|
264
|
+
}
|
|
265
|
+
/**
|
|
266
|
+
* 获取单例实例
|
|
267
|
+
*
|
|
268
|
+
* @return {Router} - 路由器实例
|
|
269
|
+
*/
|
|
270
|
+
static get instance() {
|
|
271
|
+
if (!f(R, m))
|
|
272
|
+
throw new Error("[Vitarx.Router.instance]:路由器实例未初始化");
|
|
273
|
+
return f(R, m);
|
|
274
|
+
}
|
|
275
|
+
/**
|
|
276
|
+
* 是否运行在浏览器端
|
|
277
|
+
*/
|
|
278
|
+
get isBrowser() {
|
|
279
|
+
return this._isBrowser;
|
|
280
|
+
}
|
|
281
|
+
/**
|
|
282
|
+
* 滚动行为
|
|
283
|
+
*
|
|
284
|
+
* 如果options.scrollBehavior为函数,则scrollBehavior固定为auto'。
|
|
285
|
+
*/
|
|
286
|
+
get scrollBehavior() {
|
|
287
|
+
return this._scrollBehavior;
|
|
288
|
+
}
|
|
289
|
+
/**
|
|
290
|
+
* 获取配置
|
|
291
|
+
*
|
|
292
|
+
* @return {Readonly<InitializedRouterOptions>} - 初始化配置
|
|
293
|
+
*/
|
|
294
|
+
get options() {
|
|
295
|
+
return this._options;
|
|
296
|
+
}
|
|
297
|
+
/**
|
|
298
|
+
* 路由器模式
|
|
299
|
+
*/
|
|
300
|
+
get mode() {
|
|
301
|
+
return this._options.mode;
|
|
302
|
+
}
|
|
303
|
+
/**
|
|
304
|
+
* 获取所有路由映射
|
|
305
|
+
*
|
|
306
|
+
* map键值是path,值是路由对象
|
|
307
|
+
*
|
|
308
|
+
* @return {Map<string, Route>}
|
|
309
|
+
*/
|
|
310
|
+
get pathRoutes() {
|
|
311
|
+
return this._pathRoutes;
|
|
312
|
+
}
|
|
313
|
+
/**
|
|
314
|
+
* 获取所有命名路由映射
|
|
315
|
+
*
|
|
316
|
+
* map键值是name,值是路由对象
|
|
317
|
+
*
|
|
318
|
+
* @return {Map<string, Route>}
|
|
319
|
+
*/
|
|
320
|
+
get namedRoutes() {
|
|
321
|
+
return this._namedRoutes;
|
|
322
|
+
}
|
|
323
|
+
/**
|
|
324
|
+
* 动态路由记录
|
|
325
|
+
*
|
|
326
|
+
* map键值是path段长度,值是Array<{regex: RegExp,route:RouteNormalized}>
|
|
327
|
+
*/
|
|
328
|
+
get dynamicRoutes() {
|
|
329
|
+
return this._dynamicRoutes;
|
|
330
|
+
}
|
|
331
|
+
/**
|
|
332
|
+
* ## 获取已规范的路由表
|
|
333
|
+
*
|
|
334
|
+
* 它的内存地址始终指向的是初始化时传入的路由表,但它的数据结构是经过内部规范化处理过的。
|
|
335
|
+
*
|
|
336
|
+
* 所有嵌套`Route`的path都会被自动补全为完整的路径
|
|
337
|
+
*
|
|
338
|
+
* > 注意:不要尝试修改已规范化的路由表!请使用`removeRoute`和`addRoute`方法实现路由的变更。
|
|
339
|
+
*
|
|
340
|
+
* @return {RouteNormalized[]}
|
|
341
|
+
*/
|
|
342
|
+
get routes() {
|
|
343
|
+
return this._options.routes;
|
|
344
|
+
}
|
|
345
|
+
/**
|
|
346
|
+
* 基本路径
|
|
347
|
+
*/
|
|
348
|
+
get basePath() {
|
|
349
|
+
return this._options.base;
|
|
350
|
+
}
|
|
351
|
+
/**
|
|
352
|
+
* 判断路由器是否初始化完成
|
|
353
|
+
*
|
|
354
|
+
* @return {boolean} - 如果初始化完成,返回true,否则返回false
|
|
355
|
+
*/
|
|
356
|
+
get initialized() {
|
|
357
|
+
return f(R, m) !== void 0;
|
|
358
|
+
}
|
|
359
|
+
/**
|
|
360
|
+
* 受支持的`path`后缀名
|
|
361
|
+
*/
|
|
362
|
+
get suffix() {
|
|
363
|
+
return this._options.suffix;
|
|
364
|
+
}
|
|
365
|
+
/**
|
|
366
|
+
* 当前路由数据
|
|
367
|
+
*
|
|
368
|
+
* 它是只读的,不要在外部修改它!
|
|
369
|
+
*
|
|
370
|
+
* @return {Readonly<RouteLocation>} - 当前路由数据
|
|
371
|
+
*/
|
|
372
|
+
get currentRouteLocation() {
|
|
373
|
+
return this._currentRouteLocation;
|
|
374
|
+
}
|
|
375
|
+
/**
|
|
376
|
+
* 是否处于等待状态
|
|
377
|
+
*
|
|
378
|
+
* @protected
|
|
379
|
+
*/
|
|
380
|
+
get isPendingNavigation() {
|
|
381
|
+
return !!(this._pendingReplace || this._pendingPush);
|
|
382
|
+
}
|
|
383
|
+
/**
|
|
384
|
+
* 等待替换完成的数据
|
|
385
|
+
*
|
|
386
|
+
* @protected
|
|
387
|
+
*/
|
|
388
|
+
get pendingReplaceData() {
|
|
389
|
+
return this._pendingReplace;
|
|
390
|
+
}
|
|
391
|
+
/**
|
|
392
|
+
* 等待跳转完成的数据
|
|
393
|
+
*
|
|
394
|
+
* @protected
|
|
395
|
+
*/
|
|
396
|
+
get pendingPushData() {
|
|
397
|
+
return this._pendingPush;
|
|
398
|
+
}
|
|
399
|
+
/**
|
|
400
|
+
* 路由视图
|
|
401
|
+
*
|
|
402
|
+
* 内部方法,用于获取路由线路对应的视图元素虚拟节点。
|
|
403
|
+
*
|
|
404
|
+
* @internal
|
|
405
|
+
* @param {RouteNormalized} route - 路由对象
|
|
406
|
+
* @param {string} name - 视图名称
|
|
407
|
+
* @return {VNode<WidgetType> | undefined} - 视图元素虚拟节点
|
|
408
|
+
*/
|
|
409
|
+
static routeView(t, i) {
|
|
410
|
+
const n = t.widget;
|
|
411
|
+
if (!n.hasOwnProperty(i)) return;
|
|
412
|
+
const s = n[i];
|
|
413
|
+
return at(s) ? V(q, { children: s, key: t.path }) : V(s);
|
|
414
|
+
}
|
|
415
|
+
/**
|
|
416
|
+
* 后退到上一个历史记录
|
|
417
|
+
*/
|
|
418
|
+
back() {
|
|
419
|
+
return this.go(-1);
|
|
420
|
+
}
|
|
421
|
+
/**
|
|
422
|
+
* 前进到下一个历史记录
|
|
423
|
+
*/
|
|
424
|
+
forward() {
|
|
425
|
+
return this.go(1);
|
|
426
|
+
}
|
|
427
|
+
/**
|
|
428
|
+
* 替换当前页面
|
|
429
|
+
*
|
|
430
|
+
* @param {RouteTarget} target - 目标
|
|
431
|
+
* @return {boolean} - 是否跳转成功,非内存模式始终返回true
|
|
432
|
+
*/
|
|
433
|
+
replace(t) {
|
|
434
|
+
return typeof t == "string" ? this.navigate({ index: t, isReplace: !0 }) : (t.isReplace = !0, this.navigate(t));
|
|
435
|
+
}
|
|
436
|
+
/**
|
|
437
|
+
* 跳转到新的页面
|
|
438
|
+
*
|
|
439
|
+
* @param {RouteTarget} target - 目标
|
|
440
|
+
* @return {boolean} - 是否跳转成功,非内存模式始终返回true
|
|
441
|
+
*/
|
|
442
|
+
push(t) {
|
|
443
|
+
return typeof t == "string" ? this.navigate({ index: t, isReplace: !1 }) : (t.isReplace = !1, this.navigate(t));
|
|
444
|
+
}
|
|
445
|
+
/**
|
|
446
|
+
* 删除路由
|
|
447
|
+
*
|
|
448
|
+
* @param {string} index 路由索引,如果/开头则匹配path,其他匹配name
|
|
449
|
+
* @param {boolean} isRemoveFromRoutes 是否从路由表中移除,内部递归时传递的参数,无需外部传入!
|
|
450
|
+
*/
|
|
451
|
+
removeRoute(t, i = !0) {
|
|
452
|
+
const n = this.findRoute(t);
|
|
453
|
+
if (n) {
|
|
454
|
+
if (H(n))
|
|
455
|
+
for (const s of n.children)
|
|
456
|
+
this.removeRoute(s.path, !1);
|
|
457
|
+
this._pathRoutes.delete(n.path), n.name && this._namedRoutes.delete(n.name), this.removeDynamicRoute(n.path), i && this.removedFromRoutes(n);
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
/**
|
|
461
|
+
* 添加路由
|
|
462
|
+
*
|
|
463
|
+
* @param {Route} route - 路由描述对象
|
|
464
|
+
* @param {string} parent - 父路由的path或name,不传入则添加至路由表根节点
|
|
465
|
+
*/
|
|
466
|
+
addRoute(t, i) {
|
|
467
|
+
if (i) {
|
|
468
|
+
const n = this.findRoute(i);
|
|
469
|
+
if (!n) throw new Error(`[Vitarx.Router.addRoute][ERROR]:父路由${i}不存在`);
|
|
470
|
+
this.registerRoute(t, n);
|
|
471
|
+
} else
|
|
472
|
+
this.registerRoute(t), this._options.routes.push(t);
|
|
473
|
+
}
|
|
474
|
+
/**
|
|
475
|
+
* 超找路由
|
|
476
|
+
*
|
|
477
|
+
* 传入的是`path`则会调用`matchRoute`方法,传入的是`name`则会调用`getNamedRoute`方法
|
|
478
|
+
*
|
|
479
|
+
* @param {RouteIndex|RouteTarget} target - 路由索引,如果index以/开头则匹配path,其他匹配name
|
|
480
|
+
* @return {RouteNormalized | undefined} - 路由对象,如果不存在则返回undefined
|
|
481
|
+
*/
|
|
482
|
+
findRoute(t) {
|
|
483
|
+
const i = typeof t == "object", n = i ? t.index : t;
|
|
484
|
+
if (typeof n != "string")
|
|
485
|
+
throw new TypeError(
|
|
486
|
+
`[Vitarx.Router.getRoute][ERROR]:路由索引${t}类型错误,必须给定字符串类型`
|
|
487
|
+
);
|
|
488
|
+
if (n.startsWith("/")) {
|
|
489
|
+
const s = this.matchRoute(n);
|
|
490
|
+
return s ? (s.params && i && (t.params = Object.assign(t.params || {}, s.params)), s.route) : void 0;
|
|
491
|
+
}
|
|
492
|
+
return this.findNamedRoute(n);
|
|
493
|
+
}
|
|
494
|
+
/**
|
|
495
|
+
* 查找命名路由
|
|
496
|
+
*
|
|
497
|
+
* @param {string} name - 路由名称
|
|
498
|
+
*/
|
|
499
|
+
findNamedRoute(t) {
|
|
500
|
+
return this._namedRoutes.get(t);
|
|
501
|
+
}
|
|
502
|
+
/**
|
|
503
|
+
* 初始化路由器
|
|
504
|
+
*
|
|
505
|
+
* 只能初始化一次,多次初始化无效。
|
|
506
|
+
*
|
|
507
|
+
* 如果你使用的`createRouter(options)`助手函数创建的路由器实例则无需调用该方法。
|
|
508
|
+
*
|
|
509
|
+
* @return {this} - 返回当前路由器实例
|
|
510
|
+
*/
|
|
511
|
+
initialize() {
|
|
512
|
+
return f(R, m) ? this : (this.setupRoutes(this._options.routes), typeof this.options.scrollBehavior == "function" ? this._scrollBehaviorHandler = this.options.scrollBehavior : this._scrollBehavior = this.options.scrollBehavior, this.initializeRouter(), v(R, m, this), this);
|
|
513
|
+
}
|
|
514
|
+
/**
|
|
515
|
+
* 此方法用于浏览器端滚动到指定位置
|
|
516
|
+
*
|
|
517
|
+
* @param scrollTarget
|
|
518
|
+
* @protected
|
|
519
|
+
*/
|
|
520
|
+
scrollTo(t) {
|
|
521
|
+
if (!(this.isBrowser || !t || typeof t != "object")) {
|
|
522
|
+
if ("el" in t) {
|
|
523
|
+
const { el: i, ...n } = t, s = typeof i == "string" ? document.querySelector(i) : i;
|
|
524
|
+
s && s instanceof Element ? s.scrollIntoView ? s.scrollIntoView({ behavior: this.scrollBehavior, ...n }) : window.scrollTo({
|
|
525
|
+
behavior: this.scrollBehavior,
|
|
526
|
+
top: s.getBoundingClientRect().top + window.scrollY,
|
|
527
|
+
// 获取元素位置并滚动
|
|
528
|
+
left: s.getBoundingClientRect().left + window.scrollX
|
|
529
|
+
}) : console.warn(`[Vitarx.Router.scrollTo][WARN]:元素${i}不存在,无法完成滚动到目标元素操作`);
|
|
530
|
+
return;
|
|
531
|
+
}
|
|
532
|
+
window.scrollTo({ behavior: this.scrollBehavior, ...t });
|
|
533
|
+
}
|
|
534
|
+
}
|
|
535
|
+
/**
|
|
536
|
+
* 获取路由的父路由
|
|
537
|
+
*
|
|
538
|
+
* @param route - 路由对象
|
|
539
|
+
* @return {RouteNormalized | undefined}
|
|
540
|
+
*/
|
|
541
|
+
findParentRoute(t) {
|
|
542
|
+
return this._parentRoute.get(t);
|
|
543
|
+
}
|
|
544
|
+
/**
|
|
545
|
+
* 该方法提供给`RouterView`完成渲染时调用
|
|
546
|
+
*
|
|
547
|
+
* @internal
|
|
548
|
+
*/
|
|
549
|
+
_completeViewRender() {
|
|
550
|
+
}
|
|
551
|
+
/**
|
|
552
|
+
* 完成导航
|
|
553
|
+
*
|
|
554
|
+
* 所有子类在完成导航的后续处理过后必须调用该方法!
|
|
555
|
+
*
|
|
556
|
+
* @param {RouteLocation} data - 如果是由`replace`或`push`方法发起的导航则无需传入此参数。
|
|
557
|
+
* @param {_ScrollToOptions} savedPosition - 保存的滚动位置信息,用于恢复滚动位置
|
|
558
|
+
* @protected
|
|
559
|
+
*/
|
|
560
|
+
completeNavigation(t, i) {
|
|
561
|
+
const n = this._currentRouteLocation;
|
|
562
|
+
if (this._completeViewRender = () => {
|
|
563
|
+
this.onScrollBehavior(this.currentRouteLocation, n, i).then(), this.onAfterEach(this.currentRouteLocation, n);
|
|
564
|
+
}, t)
|
|
565
|
+
this.updateRouteLocation(t);
|
|
566
|
+
else if (this._pendingReplace)
|
|
567
|
+
this.updateRouteLocation(this._pendingReplace);
|
|
568
|
+
else if (this._pendingPush)
|
|
569
|
+
this.updateRouteLocation(this._pendingPush);
|
|
570
|
+
else
|
|
571
|
+
throw new Error("[Vitarx.Router.completeNavigation][ERROR]:没有处于等待状态的导航请求。");
|
|
572
|
+
this._pendingReplace = null, this._pendingPush = null;
|
|
573
|
+
}
|
|
574
|
+
/**
|
|
575
|
+
* 更新当前导航数据中的query参数
|
|
576
|
+
*
|
|
577
|
+
* 会同步更新`fullPath`
|
|
578
|
+
*
|
|
579
|
+
* @param {Record<string, string>} query - 新的query参数对象
|
|
580
|
+
* @protected
|
|
581
|
+
*/
|
|
582
|
+
updateQuery(t) {
|
|
583
|
+
k(this._currentRouteLocation.query, t) || (this._currentRouteLocation.query = t, this._currentRouteLocation.fullPath = this.makeFullPath(
|
|
584
|
+
this._currentRouteLocation.path,
|
|
585
|
+
t,
|
|
586
|
+
this._currentRouteLocation.hash
|
|
587
|
+
));
|
|
588
|
+
}
|
|
589
|
+
/**
|
|
590
|
+
* 更新当前导航数据中的hash参数
|
|
591
|
+
*
|
|
592
|
+
* 会同步更新`fullPath`
|
|
593
|
+
*
|
|
594
|
+
* @param {`#${string}` | ''} hash - 新的hash参数,如果为空则表示无hash
|
|
595
|
+
* @protected
|
|
596
|
+
*/
|
|
597
|
+
updateHash(t) {
|
|
598
|
+
typeof t != "string" && console.warn(`[Vitarx.Router.updateHash][WARN]:hash值只能是字符串类型,给定${t}`);
|
|
599
|
+
const i = W(t);
|
|
600
|
+
i !== this._currentRouteLocation.hash && (this._currentRouteLocation.hash = i, this._currentRouteLocation.fullPath = this.makeFullPath(
|
|
601
|
+
this._currentRouteLocation.path,
|
|
602
|
+
this._currentRouteLocation.query,
|
|
603
|
+
i
|
|
604
|
+
));
|
|
605
|
+
}
|
|
606
|
+
/**
|
|
607
|
+
* 路由匹配
|
|
608
|
+
*
|
|
609
|
+
*
|
|
610
|
+
* @param {string} path - 路径
|
|
611
|
+
*
|
|
612
|
+
* @return {MatchResult} 如果匹配失败则返回undefined
|
|
613
|
+
*/
|
|
614
|
+
matchRoute(t) {
|
|
615
|
+
if (t = d(t), this._options.strict || (t = t.toLowerCase()), this.suffix) {
|
|
616
|
+
const { path: s, suffix: r } = lt(t);
|
|
617
|
+
if (!this.isAllowedSuffix(r))
|
|
618
|
+
return;
|
|
619
|
+
t = s;
|
|
620
|
+
}
|
|
621
|
+
if (this._pathRoutes.has(t))
|
|
622
|
+
return { route: this._pathRoutes.get(t), params: void 0 };
|
|
623
|
+
const i = t.split("/").filter(Boolean).length, n = this._dynamicRoutes.get(i);
|
|
624
|
+
if (n) {
|
|
625
|
+
t = `${t}/`;
|
|
626
|
+
for (const { regex: s, route: r } of n) {
|
|
627
|
+
const o = s.exec(t);
|
|
628
|
+
if (o) {
|
|
629
|
+
const u = {};
|
|
630
|
+
return Object.keys(r.pattern).forEach((h, c) => {
|
|
631
|
+
u[h] = o[c + 1];
|
|
632
|
+
}), { route: r, params: u };
|
|
633
|
+
}
|
|
634
|
+
}
|
|
635
|
+
}
|
|
636
|
+
}
|
|
637
|
+
/**
|
|
638
|
+
* 创建完整路径
|
|
639
|
+
*
|
|
640
|
+
* @protected
|
|
641
|
+
* @param path - 路径
|
|
642
|
+
* @param query - ?查询参数
|
|
643
|
+
* @param hash - #哈希值
|
|
644
|
+
*/
|
|
645
|
+
makeFullPath(t, i, n) {
|
|
646
|
+
return n && !n.startsWith("#") && (n = `#${n}`), typeof i == "object" && (i = ht(i)), this.mode === "hash" ? d(`${this.basePath}/#${t}${i}${n}`) : d(`${this.basePath}${t}${i}${n}`);
|
|
647
|
+
}
|
|
648
|
+
/**
|
|
649
|
+
* 判断是否相同的导航请求
|
|
650
|
+
*
|
|
651
|
+
* @param to
|
|
652
|
+
* @param from
|
|
653
|
+
* @protected
|
|
654
|
+
*/
|
|
655
|
+
isSameNavigate(t, i) {
|
|
656
|
+
return k(t, i);
|
|
657
|
+
}
|
|
658
|
+
/**
|
|
659
|
+
* 根据路由目标创建导航数据
|
|
660
|
+
*
|
|
661
|
+
* @param {RouteTarget} target - 路由目标
|
|
662
|
+
* @protected
|
|
663
|
+
*/
|
|
664
|
+
createRouteLocation(t) {
|
|
665
|
+
if (ft(t)) return t;
|
|
666
|
+
const i = this.findRoute(t), { index: n, query: s = {}, params: r = {}, hash: o = "" } = t;
|
|
667
|
+
let u;
|
|
668
|
+
const a = [];
|
|
669
|
+
if (i) {
|
|
670
|
+
let _ = Y(n);
|
|
671
|
+
this.suffix && _ && !i.path.endsWith(_) ? u = S(i.path + _, r) : u = S(i.path, r);
|
|
672
|
+
let E = this.findParentRoute(i);
|
|
673
|
+
for (; E; )
|
|
674
|
+
E.widget && a.unshift(E), E = this.findParentRoute(E);
|
|
675
|
+
a.push(i);
|
|
676
|
+
} else
|
|
677
|
+
u = d(n);
|
|
678
|
+
const h = W(o), c = this.makeFullPath(u, s, h);
|
|
679
|
+
return {
|
|
680
|
+
index: n,
|
|
681
|
+
path: u,
|
|
682
|
+
hash: h,
|
|
683
|
+
fullPath: c,
|
|
684
|
+
params: r,
|
|
685
|
+
query: s,
|
|
686
|
+
matched: a
|
|
687
|
+
};
|
|
688
|
+
}
|
|
689
|
+
/**
|
|
690
|
+
* 触发路由前置守卫
|
|
691
|
+
*
|
|
692
|
+
* @param {DeepReadonly<RouteLocation>} to - 路由目标对象
|
|
693
|
+
* @param {DeepReadonly<RouteLocation>} from - 前路由对象
|
|
694
|
+
* @return {false | RouteTarget} - 返回false表示阻止导航,返回新的路由目标对象则表示导航到新的目标
|
|
695
|
+
*/
|
|
696
|
+
onBeforeEach(t, i) {
|
|
697
|
+
var n;
|
|
698
|
+
return (n = this._options.beforeEach) == null ? void 0 : n.call(this, t, i);
|
|
699
|
+
}
|
|
700
|
+
/**
|
|
701
|
+
* 触发路由后置守卫
|
|
702
|
+
*
|
|
703
|
+
* @param {DeepReadonly<RouteLocation>} to - 路由目标对象
|
|
704
|
+
* @param {DeepReadonly<RouteLocation>} from - 前路由对象
|
|
705
|
+
*/
|
|
706
|
+
onAfterEach(t, i) {
|
|
707
|
+
var n;
|
|
708
|
+
return (n = this._options.afterEach) == null ? void 0 : n.call(this, t, i);
|
|
709
|
+
}
|
|
710
|
+
/**
|
|
711
|
+
* 路由跳转的通用方法
|
|
712
|
+
*
|
|
713
|
+
* 仅供内部使用,外部请使用`push`|`replace`方法
|
|
714
|
+
*
|
|
715
|
+
* @protected
|
|
716
|
+
* @param {RouteTarget} target - 目标
|
|
717
|
+
* @return {Promise<NavigateResult>} - 是否导航成功
|
|
718
|
+
*/
|
|
719
|
+
navigate(t) {
|
|
720
|
+
const i = ++this._taskCounter;
|
|
721
|
+
this._currentTaskId = i;
|
|
722
|
+
const n = () => this._currentTaskId === i, s = K(this.currentRouteLocation), r = async (o, u) => {
|
|
723
|
+
const a = this.createRouteLocation(o), h = (c = {}) => ({
|
|
724
|
+
from: s,
|
|
725
|
+
to: a,
|
|
726
|
+
status: g.success,
|
|
727
|
+
message: "导航成功",
|
|
728
|
+
redirectFrom: u ? t : void 0,
|
|
729
|
+
...c
|
|
730
|
+
});
|
|
731
|
+
if (this.isSameNavigate(a, this.currentRouteLocation))
|
|
732
|
+
return h({
|
|
733
|
+
status: g.duplicated,
|
|
734
|
+
message: "导航到相同的路由,被系统阻止!"
|
|
735
|
+
});
|
|
736
|
+
try {
|
|
737
|
+
const c = await this.onBeforeEach(a, this.currentRouteLocation);
|
|
738
|
+
return c === !1 ? h({
|
|
739
|
+
status: g.aborted,
|
|
740
|
+
message: "导航被前置守卫钩子阻止"
|
|
741
|
+
}) : n() ? typeof c == "object" && c.index !== o.index ? (c.isReplace ?? (c.isReplace = !1), r(c, !0)) : a.matched.length ? (o.isReplace ? (this._pendingReplace = a, this.replaceHistory(a)) : (this._pendingPush = a, this.pushHistory(a)), h()) : h({
|
|
742
|
+
status: g.not_matched,
|
|
743
|
+
message: "未匹配到任何路由规则,被系统阻止!请检测目标索引是否正确。"
|
|
744
|
+
}) : h({
|
|
745
|
+
status: g.cancelled,
|
|
746
|
+
message: "已被新的导航请求替代,取消此次导航!"
|
|
747
|
+
});
|
|
748
|
+
} catch (c) {
|
|
749
|
+
return console.error("[Vitarx.Router.navigate][ERROR]:导航时捕获到了异常", c), h({
|
|
750
|
+
status: g.exception,
|
|
751
|
+
message: "导航时捕获到了异常",
|
|
752
|
+
error: c
|
|
753
|
+
});
|
|
754
|
+
}
|
|
755
|
+
};
|
|
756
|
+
return r(t, !1);
|
|
757
|
+
}
|
|
758
|
+
/**
|
|
759
|
+
* 更新路由数据
|
|
760
|
+
*
|
|
761
|
+
* @private
|
|
762
|
+
* @param {RouteLocation} newLocation - 新的路由数据对象
|
|
763
|
+
*/
|
|
764
|
+
updateRouteLocation(t) {
|
|
765
|
+
Rt(this._currentRouteLocation, t);
|
|
766
|
+
}
|
|
767
|
+
/**
|
|
768
|
+
* 判断是否为允许的后缀
|
|
769
|
+
*
|
|
770
|
+
* @param suffix
|
|
771
|
+
* @private
|
|
772
|
+
*/
|
|
773
|
+
isAllowedSuffix(t) {
|
|
774
|
+
return t ? this.suffix ? this.suffix === "*" ? !0 : Array.isArray(this.suffix) ? this.suffix.includes(t) : this.suffix === t : !1 : !0;
|
|
775
|
+
}
|
|
776
|
+
/**
|
|
777
|
+
* 触发滚动行为
|
|
778
|
+
*
|
|
779
|
+
* @param {RouteLocation} to - 目标导航数据对象
|
|
780
|
+
* @param {RouteLocation} from - 前导航数据对象
|
|
781
|
+
* @param {_ScrollToOptions | undefined} savedPosition - 保存的滚动位置
|
|
782
|
+
* @private
|
|
783
|
+
*/
|
|
784
|
+
async onScrollBehavior(t, i, n) {
|
|
785
|
+
try {
|
|
786
|
+
if (this._scrollBehaviorHandler) {
|
|
787
|
+
const s = await this._scrollBehaviorHandler(t, i, n);
|
|
788
|
+
s && this.scrollTo(s);
|
|
789
|
+
} else
|
|
790
|
+
this.scrollTo(n);
|
|
791
|
+
} catch (s) {
|
|
792
|
+
console.error("[Vitarx.Router.onScrollBehavior]['ERROR']:处理滚动行为时捕获到了异常", s);
|
|
793
|
+
}
|
|
794
|
+
}
|
|
795
|
+
/**
|
|
796
|
+
* 从源路由表中删除路由
|
|
797
|
+
*
|
|
798
|
+
* @param route
|
|
799
|
+
* @protected
|
|
800
|
+
*/
|
|
801
|
+
removedFromRoutes(t) {
|
|
802
|
+
const i = this.findParentRoute(t);
|
|
803
|
+
if (i != null && i.children) {
|
|
804
|
+
const n = i.children.indexOf(t);
|
|
805
|
+
n !== -1 && i.children.splice(n, 1);
|
|
806
|
+
} else {
|
|
807
|
+
const n = this._options.routes.indexOf(t);
|
|
808
|
+
n !== -1 && this._options.routes.splice(n, 1);
|
|
809
|
+
}
|
|
810
|
+
}
|
|
811
|
+
/**
|
|
812
|
+
* 删除动态路由映射
|
|
813
|
+
*
|
|
814
|
+
* @param path
|
|
815
|
+
* @protected
|
|
816
|
+
*/
|
|
817
|
+
removeDynamicRoute(t) {
|
|
818
|
+
if (!O(t)) return;
|
|
819
|
+
const n = t.split("/").filter(Boolean).length, s = (o) => {
|
|
820
|
+
const u = this._dynamicRoutes.get(o);
|
|
821
|
+
if (u) {
|
|
822
|
+
for (let a = 0; a < u.length; a++)
|
|
823
|
+
if (u[a].route.path === t) {
|
|
824
|
+
u.splice(a, 1);
|
|
825
|
+
break;
|
|
826
|
+
}
|
|
827
|
+
}
|
|
828
|
+
};
|
|
829
|
+
s(n);
|
|
830
|
+
const r = ot(t);
|
|
831
|
+
if (r > 0)
|
|
832
|
+
for (let o = 1; o <= r; o++)
|
|
833
|
+
s(n - o);
|
|
834
|
+
}
|
|
835
|
+
/**
|
|
836
|
+
* 初始化路由表
|
|
837
|
+
*
|
|
838
|
+
* @param routes
|
|
839
|
+
*/
|
|
840
|
+
setupRoutes(t) {
|
|
841
|
+
for (const i of t)
|
|
842
|
+
this.registerRoute(i);
|
|
843
|
+
}
|
|
844
|
+
/**
|
|
845
|
+
* 注册路由
|
|
846
|
+
*
|
|
847
|
+
* @param {Route} route - 路由对象
|
|
848
|
+
* @param {RouteNormalized} group - 路由所在的分组
|
|
849
|
+
* @protected
|
|
850
|
+
*/
|
|
851
|
+
registerRoute(t, i) {
|
|
852
|
+
const n = dt(t);
|
|
853
|
+
if (i && (n.path = d(`${i.path}${n.path}`), this._parentRoute.set(n, i)), H(n)) {
|
|
854
|
+
t.widget && this.recordRoute(n);
|
|
855
|
+
for (const s of n.children)
|
|
856
|
+
this.registerRoute(s, n);
|
|
857
|
+
} else
|
|
858
|
+
this.recordRoute(n);
|
|
859
|
+
}
|
|
860
|
+
/**
|
|
861
|
+
* 如果路径是严格匹配,则转换为小写
|
|
862
|
+
*
|
|
863
|
+
* @param path
|
|
864
|
+
* @private
|
|
865
|
+
*/
|
|
866
|
+
strictPath(t) {
|
|
867
|
+
return this._options.strict ? t : t.toLowerCase();
|
|
868
|
+
}
|
|
869
|
+
/**
|
|
870
|
+
* 记录路由
|
|
871
|
+
*
|
|
872
|
+
* @param {Route} route - 路由对象
|
|
873
|
+
* @protected
|
|
874
|
+
*/
|
|
875
|
+
recordRoute(t) {
|
|
876
|
+
if (t.name) {
|
|
877
|
+
if (t.name.startsWith("/") && (t.name = t.name.replace(/^\//, ""), console.warn(
|
|
878
|
+
`[Vitarx.Router][WARN]:命名路由(name)不要以/开头: ${t.name},因为内部需要使用/区分path、name`
|
|
879
|
+
)), this._namedRoutes.has(t.name))
|
|
880
|
+
throw new Error(`[Vitarx.Router][ERROR]:检测到重复的路由名称(name): ${t.name}`);
|
|
881
|
+
this._namedRoutes.set(t.name, t);
|
|
882
|
+
}
|
|
883
|
+
const i = this.strictPath(t.path);
|
|
884
|
+
if (this._pathRoutes.has(i))
|
|
885
|
+
throw new Error(`[Vitarx.Router][ERROR]:检测到重复的路由路径(path): ${t.path}`);
|
|
886
|
+
this._pathRoutes.set(i, t), O(t.path) && this.recordDynamicRoute(t);
|
|
887
|
+
}
|
|
888
|
+
/**
|
|
889
|
+
* 添加动态路由
|
|
890
|
+
* @param route
|
|
891
|
+
*/
|
|
892
|
+
recordDynamicRoute(t) {
|
|
893
|
+
const { regex: i, length: n, optional: s } = ct(
|
|
894
|
+
t.path,
|
|
895
|
+
t.pattern,
|
|
896
|
+
this.options.strict,
|
|
897
|
+
this.options.pattern
|
|
898
|
+
), r = (o) => {
|
|
899
|
+
this._dynamicRoutes.has(o) || this._dynamicRoutes.set(o, []), this._dynamicRoutes.get(o).push({ regex: i, route: t });
|
|
900
|
+
};
|
|
901
|
+
if (r(n), s > 0)
|
|
902
|
+
for (let o = 1; o <= s; o++)
|
|
903
|
+
r(n - o);
|
|
904
|
+
}
|
|
905
|
+
};
|
|
906
|
+
m = new WeakMap(), /**
|
|
907
|
+
* 路由器实例,单例模式,用于全局获取路由器实例
|
|
908
|
+
*/
|
|
909
|
+
x(R, m);
|
|
910
|
+
let p = R;
|
|
911
|
+
class mt extends p {
|
|
912
|
+
constructor(t) {
|
|
913
|
+
super(t), ["path", "hash"].includes(t.mode) && (t.mode = "path"), t.mode === "hash" && this.ensureHash();
|
|
914
|
+
}
|
|
915
|
+
/**
|
|
916
|
+
* 当前路由目标
|
|
917
|
+
*
|
|
918
|
+
* @returns {RouteTarget} - 包含 index、hash 和 query 的对象
|
|
919
|
+
*/
|
|
920
|
+
get currentRouteTarget() {
|
|
921
|
+
return ut(window.location, this.mode, this.basePath);
|
|
922
|
+
}
|
|
923
|
+
/**
|
|
924
|
+
* window.history
|
|
925
|
+
*
|
|
926
|
+
* @private
|
|
927
|
+
*/
|
|
928
|
+
get webHistory() {
|
|
929
|
+
return window.history;
|
|
930
|
+
}
|
|
931
|
+
/**
|
|
932
|
+
* @inheritDoc
|
|
933
|
+
*/
|
|
934
|
+
go(t) {
|
|
935
|
+
this.webHistory.go(t);
|
|
936
|
+
}
|
|
937
|
+
/**
|
|
938
|
+
* @inheritDoc
|
|
939
|
+
*/
|
|
940
|
+
initializeRouter() {
|
|
941
|
+
window.addEventListener("popstate", this.onPopState.bind(this)), this.replace(this.currentRouteTarget).then();
|
|
942
|
+
}
|
|
943
|
+
/**
|
|
944
|
+
* @inheritDoc
|
|
945
|
+
*/
|
|
946
|
+
pushHistory(t) {
|
|
947
|
+
this.saveCurrentScrollPosition(), this.webHistory.pushState(this.createState(t), "", t.fullPath), this.completeNavigation(t);
|
|
948
|
+
}
|
|
949
|
+
/**
|
|
950
|
+
* @inheritDoc
|
|
951
|
+
*/
|
|
952
|
+
replaceHistory(t) {
|
|
953
|
+
var n;
|
|
954
|
+
const i = (n = this.webHistory.state) == null ? void 0 : n.scrollPosition;
|
|
955
|
+
this.webHistory.replaceState(this.createState(t), "", t.fullPath), this.completeNavigation(t, i);
|
|
956
|
+
}
|
|
957
|
+
/**
|
|
958
|
+
* 保存当前页面滚动位置
|
|
959
|
+
*
|
|
960
|
+
* @private
|
|
961
|
+
*/
|
|
962
|
+
saveCurrentScrollPosition() {
|
|
963
|
+
const t = {
|
|
964
|
+
left: window.scrollX,
|
|
965
|
+
top: window.scrollY,
|
|
966
|
+
behavior: this.scrollBehavior
|
|
967
|
+
};
|
|
968
|
+
this.webHistory.replaceState(
|
|
969
|
+
{
|
|
970
|
+
...this.webHistory.state,
|
|
971
|
+
scrollPosition: t
|
|
972
|
+
},
|
|
973
|
+
"",
|
|
974
|
+
window.location.href
|
|
975
|
+
);
|
|
976
|
+
}
|
|
977
|
+
/**
|
|
978
|
+
* 创建历史记录状态
|
|
979
|
+
*
|
|
980
|
+
* 用于在浏览器历史记录中存储路由信息,以支持前进、后退等操作。
|
|
981
|
+
*
|
|
982
|
+
* @param data - 路由数据
|
|
983
|
+
* @param hash - 要替换的哈希值
|
|
984
|
+
* @param query - 要替换的查询参数
|
|
985
|
+
* @private
|
|
986
|
+
*/
|
|
987
|
+
createState(t, i, n) {
|
|
988
|
+
const { matched: s, ...r } = t;
|
|
989
|
+
return typeof i == "string" && (r.hash = i), typeof n == "object" && (r.query = n), JSON.parse(JSON.stringify(r));
|
|
990
|
+
}
|
|
991
|
+
/**
|
|
992
|
+
* 处理浏览器历史记录的返回/前进事件
|
|
993
|
+
*/
|
|
994
|
+
onPopState(t) {
|
|
995
|
+
var n;
|
|
996
|
+
let i;
|
|
997
|
+
(n = t.state) != null && n.index ? i = {
|
|
998
|
+
index: t.state.index,
|
|
999
|
+
hash: t.state.hash,
|
|
1000
|
+
query: t.state.query
|
|
1001
|
+
} : i = this.currentRouteTarget, this.replace(i).then((s) => {
|
|
1002
|
+
if (!s.redirectFrom && s.status === g.not_matched && this.mode === "hash" && s.to.index.startsWith("/")) {
|
|
1003
|
+
const r = s.to.index.slice(1), o = window.document.getElementById(r);
|
|
1004
|
+
o && o.scrollIntoView({ behavior: this.scrollBehavior }), this.updateHash(`#${r}`), this.webHistory.replaceState(this.createState(s.from), "", s.from.fullPath);
|
|
1005
|
+
}
|
|
1006
|
+
});
|
|
1007
|
+
}
|
|
1008
|
+
/**
|
|
1009
|
+
* 确保路径是 hash 格式
|
|
1010
|
+
*
|
|
1011
|
+
* @private
|
|
1012
|
+
*/
|
|
1013
|
+
ensureHash() {
|
|
1014
|
+
const { pathname: t, search: i, hash: n } = window.location;
|
|
1015
|
+
if (!t.startsWith(this.basePath)) {
|
|
1016
|
+
const s = `${this.basePath}/#${t}${i}${n}`;
|
|
1017
|
+
return window.location.replace(s);
|
|
1018
|
+
}
|
|
1019
|
+
}
|
|
1020
|
+
}
|
|
1021
|
+
class C extends p {
|
|
1022
|
+
constructor(i) {
|
|
1023
|
+
super(i);
|
|
1024
|
+
// 路由历史记录数组
|
|
1025
|
+
l(this, "_history", []);
|
|
1026
|
+
// 标记是否有go方法触发的导航
|
|
1027
|
+
l(this, "_pendingGo", null);
|
|
1028
|
+
/// 当前历史路由索引
|
|
1029
|
+
l(this, "_currentIndex", 0);
|
|
1030
|
+
i.mode = "memory";
|
|
1031
|
+
}
|
|
1032
|
+
/**
|
|
1033
|
+
* 当前历史路由索引
|
|
1034
|
+
*
|
|
1035
|
+
* @protected
|
|
1036
|
+
*/
|
|
1037
|
+
get currentIndex() {
|
|
1038
|
+
return this._currentIndex;
|
|
1039
|
+
}
|
|
1040
|
+
/**
|
|
1041
|
+
* @inheritDoc
|
|
1042
|
+
*/
|
|
1043
|
+
go(i) {
|
|
1044
|
+
if (!i) return;
|
|
1045
|
+
const n = this.currentIndex, s = Math.max(0, Math.min(this._history.length - 1, n + i));
|
|
1046
|
+
if (s === n) return;
|
|
1047
|
+
const r = this._history[s];
|
|
1048
|
+
this._pendingGo = s, this.navigate(r).then((o) => {
|
|
1049
|
+
o.status !== g.success && (this._pendingGo = null);
|
|
1050
|
+
});
|
|
1051
|
+
}
|
|
1052
|
+
/**
|
|
1053
|
+
* @inheritDoc
|
|
1054
|
+
*/
|
|
1055
|
+
initializeRouter() {
|
|
1056
|
+
this._history.push(this.currentRouteLocation);
|
|
1057
|
+
}
|
|
1058
|
+
/**
|
|
1059
|
+
* 添加历史记录
|
|
1060
|
+
*/
|
|
1061
|
+
pushHistory(i) {
|
|
1062
|
+
this._updateHistory(i, !1);
|
|
1063
|
+
}
|
|
1064
|
+
/**
|
|
1065
|
+
* 替换历史记录
|
|
1066
|
+
*/
|
|
1067
|
+
replaceHistory(i) {
|
|
1068
|
+
this._updateHistory(i, !0);
|
|
1069
|
+
}
|
|
1070
|
+
/**
|
|
1071
|
+
* 更新历史记录
|
|
1072
|
+
*
|
|
1073
|
+
* @param {RouteLocation} data - 目标路由
|
|
1074
|
+
* @param {boolean} isReplace - 是否为替换操作
|
|
1075
|
+
* @private
|
|
1076
|
+
*/
|
|
1077
|
+
_updateHistory(i, n) {
|
|
1078
|
+
let s;
|
|
1079
|
+
if (this._pendingGo !== null)
|
|
1080
|
+
this._history[this._pendingGo] = i, s = this._pendingGo;
|
|
1081
|
+
else if (n)
|
|
1082
|
+
this._history[this.currentIndex] = i, s = this.currentIndex;
|
|
1083
|
+
else {
|
|
1084
|
+
const r = this.currentIndex + 1;
|
|
1085
|
+
r < this._history.length ? (this._history[r] = i, this._history.length = r + 1, s = r) : (this._history.push(i), s = this._history.length - 1);
|
|
1086
|
+
}
|
|
1087
|
+
this._currentIndex = s, this.completeNavigation(i), this._pendingGo = null;
|
|
1088
|
+
}
|
|
1089
|
+
}
|
|
1090
|
+
function _t(...e) {
|
|
1091
|
+
return e;
|
|
1092
|
+
}
|
|
1093
|
+
function xt(e) {
|
|
1094
|
+
return e;
|
|
1095
|
+
}
|
|
1096
|
+
function Pt(e) {
|
|
1097
|
+
let t;
|
|
1098
|
+
return !(window != null && window.location) && e.mode !== "memory" ? (console.warn("当前环境非浏览器端,强制使用内存模式路由"), e.mode = "memory", new C(e).initialize()) : (e.mode === "memory" ? t = new C(e) : t = new mt(e), t.initialize());
|
|
1099
|
+
}
|
|
1100
|
+
function Et() {
|
|
1101
|
+
return p.instance;
|
|
1102
|
+
}
|
|
1103
|
+
function vt() {
|
|
1104
|
+
return p.instance.currentRouteLocation;
|
|
1105
|
+
}
|
|
1106
|
+
function bt(e) {
|
|
1107
|
+
return e[F] = !0, e;
|
|
1108
|
+
}
|
|
1109
|
+
var $, y, w, P;
|
|
1110
|
+
const b = class b extends J {
|
|
1111
|
+
constructor(i) {
|
|
1112
|
+
super(i);
|
|
1113
|
+
// 自身index
|
|
1114
|
+
x(this, y);
|
|
1115
|
+
// 当前匹配的路由配置
|
|
1116
|
+
x(this, w);
|
|
1117
|
+
// 当前视图元素
|
|
1118
|
+
x(this, P, Q());
|
|
1119
|
+
const n = X(f(b, $), -1, this);
|
|
1120
|
+
v(this, y, n + 1), Z(f(b, $), f(this, y), this), v(this, w, this.matchedRoute), f(this, w) && (f(this, P).value = p.routeView(f(this, w), this.name)), N(this.location.matched, (s, r) => {
|
|
1121
|
+
const o = r[this.index];
|
|
1122
|
+
o !== f(this, w) && (v(this, w, o), f(this, P).value = o ? p.routeView(o, this.name) : void 0);
|
|
1123
|
+
});
|
|
1124
|
+
}
|
|
1125
|
+
/**
|
|
1126
|
+
* 当前路由器视图所在层级索引
|
|
1127
|
+
*
|
|
1128
|
+
* `index`的值从0开始,它与`RouteLocation.matched`数组下标一一对应
|
|
1129
|
+
*/
|
|
1130
|
+
get index() {
|
|
1131
|
+
return f(this, y);
|
|
1132
|
+
}
|
|
1133
|
+
/**
|
|
1134
|
+
* 是否为最后一个路由视图
|
|
1135
|
+
*/
|
|
1136
|
+
get isLastView() {
|
|
1137
|
+
return this.index === this.location.matched.length - 1 && this.name === "default";
|
|
1138
|
+
}
|
|
1139
|
+
/**
|
|
1140
|
+
* 视图名称
|
|
1141
|
+
*
|
|
1142
|
+
* @default 'default'
|
|
1143
|
+
*/
|
|
1144
|
+
get name() {
|
|
1145
|
+
return this.props.name || "default";
|
|
1146
|
+
}
|
|
1147
|
+
get matchedRoute() {
|
|
1148
|
+
return this.location.matched[f(this, y)];
|
|
1149
|
+
}
|
|
1150
|
+
/**
|
|
1151
|
+
* 当前路由器视图要显示的虚拟节点
|
|
1152
|
+
*
|
|
1153
|
+
* 注意未匹配时会返回`undefined`,匹配成功时返回的是`VNode<WidgetType>`
|
|
1154
|
+
*
|
|
1155
|
+
* @protected
|
|
1156
|
+
*/
|
|
1157
|
+
get currentElement() {
|
|
1158
|
+
return f(this, P).value;
|
|
1159
|
+
}
|
|
1160
|
+
/**
|
|
1161
|
+
* 当前的路由位置对象
|
|
1162
|
+
*
|
|
1163
|
+
* @protected
|
|
1164
|
+
*/
|
|
1165
|
+
get location() {
|
|
1166
|
+
return p.instance.currentRouteLocation;
|
|
1167
|
+
}
|
|
1168
|
+
/**
|
|
1169
|
+
* @inheritDoc
|
|
1170
|
+
*/
|
|
1171
|
+
onMounted() {
|
|
1172
|
+
this.completeViewRender();
|
|
1173
|
+
}
|
|
1174
|
+
/**
|
|
1175
|
+
* @inheritDoc
|
|
1176
|
+
*/
|
|
1177
|
+
onUpdated() {
|
|
1178
|
+
this.completeViewRender();
|
|
1179
|
+
}
|
|
1180
|
+
/**
|
|
1181
|
+
* ## 构建视图
|
|
1182
|
+
*
|
|
1183
|
+
* 可以重写该方法添加自定义的视图元素
|
|
1184
|
+
*
|
|
1185
|
+
* 例如,使用`KeepAlive`组件缓存当前视图元素:
|
|
1186
|
+
* ```tsx
|
|
1187
|
+
* protected build() {
|
|
1188
|
+
* // 不可省略,因为`KeepAlive`不能渲染非组件节点。
|
|
1189
|
+
* if (!this.currentElement) return <></> // 使用空片段节点占位
|
|
1190
|
+
*
|
|
1191
|
+
* // 将当前显示的视图元素(VNode<WidgetType>对象)传递给`KeepAlive`插槽,使用缓存功能。
|
|
1192
|
+
* return <KeepAlive onlyKey={this.matchedRoute?.path}>{this.currentElement}</KeepAlive>
|
|
1193
|
+
* }
|
|
1194
|
+
* ```
|
|
1195
|
+
* @protected
|
|
1196
|
+
*/
|
|
1197
|
+
build() {
|
|
1198
|
+
return this.currentElement || V(tt);
|
|
1199
|
+
}
|
|
1200
|
+
/**
|
|
1201
|
+
* 视图渲染完成通知路由器
|
|
1202
|
+
*
|
|
1203
|
+
* @private
|
|
1204
|
+
*/
|
|
1205
|
+
completeViewRender() {
|
|
1206
|
+
this.isLastView && p.instance._completeViewRender();
|
|
1207
|
+
}
|
|
1208
|
+
};
|
|
1209
|
+
$ = new WeakMap(), y = new WeakMap(), w = new WeakMap(), P = new WeakMap(), x(b, $, Symbol("RouterViewCounter"));
|
|
1210
|
+
let z = b;
|
|
1211
|
+
export {
|
|
1212
|
+
C as MemoryRouter,
|
|
1213
|
+
g as NavigateStatus,
|
|
1214
|
+
p as Router,
|
|
1215
|
+
z as RouterView,
|
|
1216
|
+
mt as WebHistoryRouter,
|
|
1217
|
+
Pt as createRouter,
|
|
1218
|
+
xt as defineRoute,
|
|
1219
|
+
_t as defineRoutes,
|
|
1220
|
+
bt as lazy,
|
|
1221
|
+
vt as useRoute,
|
|
1222
|
+
Et as useRouter
|
|
1223
|
+
};
|