@esmx/router 3.0.0-rc.12

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.
Files changed (61) hide show
  1. package/dist/history/abstract.d.ts +29 -0
  2. package/dist/history/abstract.mjs +107 -0
  3. package/dist/history/base.d.ts +79 -0
  4. package/dist/history/base.mjs +275 -0
  5. package/dist/history/html.d.ts +22 -0
  6. package/dist/history/html.mjs +181 -0
  7. package/dist/history/index.d.ts +7 -0
  8. package/dist/history/index.mjs +16 -0
  9. package/dist/index.d.ts +3 -0
  10. package/dist/index.mjs +3 -0
  11. package/dist/matcher/create-matcher.d.ts +5 -0
  12. package/dist/matcher/create-matcher.mjs +218 -0
  13. package/dist/matcher/create-matcher.spec.d.ts +1 -0
  14. package/dist/matcher/create-matcher.spec.mjs +0 -0
  15. package/dist/matcher/index.d.ts +1 -0
  16. package/dist/matcher/index.mjs +1 -0
  17. package/dist/router.d.ts +111 -0
  18. package/dist/router.mjs +399 -0
  19. package/dist/task-pipe/index.d.ts +1 -0
  20. package/dist/task-pipe/index.mjs +1 -0
  21. package/dist/task-pipe/task.d.ts +30 -0
  22. package/dist/task-pipe/task.mjs +66 -0
  23. package/dist/utils/bom.d.ts +5 -0
  24. package/dist/utils/bom.mjs +10 -0
  25. package/dist/utils/encoding.d.ts +48 -0
  26. package/dist/utils/encoding.mjs +44 -0
  27. package/dist/utils/guards.d.ts +9 -0
  28. package/dist/utils/guards.mjs +12 -0
  29. package/dist/utils/index.d.ts +7 -0
  30. package/dist/utils/index.mjs +27 -0
  31. package/dist/utils/path.d.ts +60 -0
  32. package/dist/utils/path.mjs +264 -0
  33. package/dist/utils/path.spec.d.ts +1 -0
  34. package/dist/utils/path.spec.mjs +30 -0
  35. package/dist/utils/scroll.d.ts +25 -0
  36. package/dist/utils/scroll.mjs +59 -0
  37. package/dist/utils/utils.d.ts +16 -0
  38. package/dist/utils/utils.mjs +11 -0
  39. package/dist/utils/warn.d.ts +2 -0
  40. package/dist/utils/warn.mjs +12 -0
  41. package/package.json +66 -0
  42. package/src/history/abstract.ts +149 -0
  43. package/src/history/base.ts +408 -0
  44. package/src/history/html.ts +231 -0
  45. package/src/history/index.ts +20 -0
  46. package/src/index.ts +3 -0
  47. package/src/matcher/create-matcher.spec.ts +3 -0
  48. package/src/matcher/create-matcher.ts +293 -0
  49. package/src/matcher/index.ts +1 -0
  50. package/src/router.ts +521 -0
  51. package/src/task-pipe/index.ts +1 -0
  52. package/src/task-pipe/task.ts +97 -0
  53. package/src/utils/bom.ts +14 -0
  54. package/src/utils/encoding.ts +153 -0
  55. package/src/utils/guards.ts +25 -0
  56. package/src/utils/index.ts +27 -0
  57. package/src/utils/path.spec.ts +44 -0
  58. package/src/utils/path.ts +397 -0
  59. package/src/utils/scroll.ts +120 -0
  60. package/src/utils/utils.ts +30 -0
  61. package/src/utils/warn.ts +13 -0
@@ -0,0 +1,399 @@
1
+ import URLParse from "url-parse";
2
+ import { createHistory } from "./history/index.mjs";
3
+ import { createRouterMatcher } from "./matcher/index.mjs";
4
+ import {
5
+ RouterMode,
6
+ StateLayerConfigKey
7
+ } from "./types";
8
+ import { inBrowser, normalizePath, regexDomain } from "./utils/index.mjs";
9
+ const baseValue = Number(Date.now());
10
+ let layerIdOffset = 0;
11
+ function getLatestLayerId() {
12
+ return baseValue + ++layerIdOffset;
13
+ }
14
+ export class Router {
15
+ /**
16
+ * 当前路由对象的上级路由对象
17
+ */
18
+ parent = null;
19
+ /* 路由配置 */
20
+ options;
21
+ /**
22
+ * 路由固定前置路径
23
+ * 需要注意的是如果使用函数返回 base,需要尽量保证相同的路径返回相同base
24
+ */
25
+ base;
26
+ /* 路由模式 */
27
+ mode;
28
+ /* 路由匹配器 */
29
+ matcher;
30
+ /* 路由history类 */
31
+ history;
32
+ /* 滚动行为 */
33
+ scrollBehavior;
34
+ /* 当前路由信息 */
35
+ route = {
36
+ href: "",
37
+ origin: "",
38
+ host: "",
39
+ protocol: "",
40
+ hostname: "",
41
+ port: "",
42
+ pathname: "",
43
+ search: "",
44
+ hash: "",
45
+ params: {},
46
+ query: {},
47
+ queryArray: {},
48
+ state: {},
49
+ meta: {},
50
+ base: "",
51
+ path: "",
52
+ fullPath: "",
53
+ matched: []
54
+ };
55
+ constructor(options) {
56
+ this.options = options;
57
+ this.matcher = createRouterMatcher(options.routes || []);
58
+ this.mode = options.mode || (inBrowser ? RouterMode.HISTORY : RouterMode.ABSTRACT);
59
+ this.base = options.base || "";
60
+ this.scrollBehavior = options.scrollBehavior || ((to, from, savedPosition) => {
61
+ if (savedPosition) return savedPosition;
62
+ return {
63
+ left: 0,
64
+ top: 0
65
+ };
66
+ });
67
+ this.history = createHistory({
68
+ router: this,
69
+ mode: this.mode
70
+ });
71
+ }
72
+ /* 更新路由 */
73
+ updateRoute(route) {
74
+ var _a, _b, _c, _d, _e, _f;
75
+ const curAppType = (_b = (_a = this.route) == null ? void 0 : _a.matched[0]) == null ? void 0 : _b.appType;
76
+ const appType = (_c = route.matched[0]) == null ? void 0 : _c.appType;
77
+ this.applyRoute(route);
78
+ const curRegisterConfig = curAppType && this.registeredConfigMap[curAppType];
79
+ const registerConfig = appType && this.registeredConfigMap[appType];
80
+ if (registerConfig) {
81
+ const { mounted, generator } = registerConfig;
82
+ if (!mounted) {
83
+ registerConfig.config = generator(this);
84
+ (_d = registerConfig.config) == null ? void 0 : _d.mount();
85
+ registerConfig.mounted = true;
86
+ this.layerMap[this.layerId] = {
87
+ router: this,
88
+ config: registerConfig.config,
89
+ destroyed: false
90
+ };
91
+ if (!this.layerConfigList.find(
92
+ (item) => item.id === this.layerId
93
+ )) {
94
+ this.layerConfigList.push({
95
+ id: this.layerId,
96
+ depth: 0
97
+ });
98
+ }
99
+ }
100
+ (_e = registerConfig.config) == null ? void 0 : _e.updated();
101
+ }
102
+ if (curAppType !== appType && curRegisterConfig) {
103
+ (_f = curRegisterConfig.config) == null ? void 0 : _f.destroy();
104
+ curRegisterConfig.mounted = false;
105
+ }
106
+ }
107
+ /* 应用路由 */
108
+ applyRoute(route) {
109
+ let url = "";
110
+ const { fullPath } = route;
111
+ if (inBrowser && !regexDomain.test(fullPath)) {
112
+ url = normalizePath(fullPath, location.origin);
113
+ } else {
114
+ url = normalizePath(fullPath);
115
+ }
116
+ const {
117
+ hash,
118
+ host,
119
+ hostname,
120
+ href,
121
+ origin,
122
+ pathname,
123
+ port,
124
+ protocol,
125
+ query
126
+ } = new URLParse(url);
127
+ Object.assign(
128
+ this.route,
129
+ {
130
+ href,
131
+ origin,
132
+ host,
133
+ protocol,
134
+ hostname,
135
+ port,
136
+ pathname,
137
+ search: query,
138
+ hash
139
+ },
140
+ route
141
+ );
142
+ }
143
+ /* 解析路由 */
144
+ resolve(location2) {
145
+ return this.history.resolve(location2);
146
+ }
147
+ /**
148
+ * 新增单个路由匹配规则
149
+ */
150
+ // addRoutes(routes: RouteConfig[]) {
151
+ // this.matcher.addRoutes(routes);
152
+ // }
153
+ /**
154
+ * 新增多个路由匹配规则
155
+ */
156
+ // addRoute(route: RouteConfig): void {
157
+ // this.matcher.addRoute(route);
158
+ // }
159
+ /* 初始化 */
160
+ async init(options = {}) {
161
+ var _a;
162
+ const { parent = null, route, replace = true } = options;
163
+ await this.history.init({
164
+ replace
165
+ });
166
+ const layerId = getLatestLayerId();
167
+ this.layerId = layerId;
168
+ let layerMap = {};
169
+ let layerConfigList = [];
170
+ if (parent && route) {
171
+ const appType = (_a = route.matched[0]) == null ? void 0 : _a.appType;
172
+ if (!appType) return;
173
+ const registerConfig = parent.registeredConfigMap[appType];
174
+ if (!registerConfig) return;
175
+ parent.freeze();
176
+ this.registeredConfigMap = parent.registeredConfigMap;
177
+ const { generator } = registerConfig;
178
+ const config = generator(this);
179
+ config.mount();
180
+ config.updated();
181
+ layerMap = parent.layerMap;
182
+ layerMap[layerId] = {
183
+ router: this,
184
+ config,
185
+ destroyed: false
186
+ };
187
+ layerConfigList = parent.layerConfigList;
188
+ }
189
+ if (!layerConfigList.find((item) => item.id === layerId)) {
190
+ layerConfigList.push({
191
+ id: layerId,
192
+ depth: 0
193
+ });
194
+ }
195
+ this.parent = parent;
196
+ this.layerMap = layerMap;
197
+ this.layerConfigList = layerConfigList;
198
+ }
199
+ /**
200
+ * 卸载方法
201
+ */
202
+ async destroy() {
203
+ }
204
+ /* 已注册的app配置 */
205
+ registeredConfigMap = {};
206
+ /* app配置注册 */
207
+ register(name, config) {
208
+ this.registeredConfigMap[name] = {
209
+ generator: config,
210
+ mounted: false
211
+ };
212
+ }
213
+ /* 全局路由守卫 */
214
+ guards = {
215
+ beforeEach: [],
216
+ afterEach: []
217
+ };
218
+ /* 注册全局路由前置守卫 */
219
+ beforeEach(guard) {
220
+ this.guards.beforeEach.push(guard);
221
+ }
222
+ /* 卸载全局路由前置守卫 */
223
+ unBindBeforeEach(guard) {
224
+ const i = this.guards.beforeEach.findIndex((item) => item === guard);
225
+ this.guards.beforeEach.splice(i, 1);
226
+ }
227
+ /* 注册全局路由后置守卫 */
228
+ afterEach(guard) {
229
+ this.guards.afterEach.push(guard);
230
+ }
231
+ /* 卸载全局路由后置守卫 */
232
+ unBindAfterEach(guard) {
233
+ const i = this.guards.afterEach.findIndex((item) => item === guard);
234
+ this.guards.afterEach.splice(i, 1);
235
+ }
236
+ /* 路由跳转方法,会创建新的历史记录 */
237
+ async push(location2) {
238
+ await this.history.push(location2);
239
+ }
240
+ /* 路由跳转方法,会替换当前的历史记录 */
241
+ async replace(location2) {
242
+ await this.history.replace(location2);
243
+ }
244
+ /**
245
+ * 当前路由弹层id,用于区分不同的路由弹层
246
+ */
247
+ layerId = 0;
248
+ /**
249
+ * 路由弹层配置
250
+ * key为路由弹层id
251
+ */
252
+ layerConfigList = [];
253
+ /**
254
+ * 路由弹层id与路由实例的map
255
+ */
256
+ layerMap = {};
257
+ /**
258
+ * 路由是否冻结
259
+ */
260
+ isFrozen = false;
261
+ /**
262
+ * 路由冻结方法
263
+ */
264
+ freeze() {
265
+ this.isFrozen = true;
266
+ }
267
+ /**
268
+ * 路由解冻方法
269
+ */
270
+ unfreeze() {
271
+ this.isFrozen = false;
272
+ }
273
+ /**
274
+ * 打开路由弹层方法,会创建新的路由实例并调用注册的 register 方法
275
+ * 服务端会使用 push 作为替代
276
+ */
277
+ async pushLayer(location2) {
278
+ if (this.isFrozen) return;
279
+ const route = this.resolve(location2);
280
+ if (route.fullPath === this.route.fullPath) return;
281
+ if (!inBrowser) {
282
+ this.push(location2);
283
+ return;
284
+ }
285
+ const router = createRouter({
286
+ ...this.options,
287
+ initUrl: route.fullPath
288
+ });
289
+ await router.init({ parent: this, route, replace: false });
290
+ }
291
+ /**
292
+ * 更新路由弹层方法
293
+ * @param state 参数为history.state
294
+ * @description 没有传入 state 时使用当前配置更新 history.state,传入了 state 时使用传入的 state 更新当前配置
295
+ */
296
+ checkLayerState(state) {
297
+ const stateLayerConfigList = state[StateLayerConfigKey] || [];
298
+ const layerConfigList = Object.keys(this.layerMap).map(Number);
299
+ const stateLayerIdList = stateLayerConfigList.map(({ id }) => id).filter((id) => {
300
+ return layerConfigList.includes(id);
301
+ });
302
+ if (stateLayerIdList.length === 0) {
303
+ return false;
304
+ }
305
+ if (stateLayerIdList.length === 1 && stateLayerIdList[0] === this.layerId) {
306
+ return false;
307
+ }
308
+ const createList = [];
309
+ const destroyList = [];
310
+ Object.entries(this.layerMap).forEach(([key, value]) => {
311
+ if (stateLayerIdList.includes(Number(key))) {
312
+ if (value.destroyed) {
313
+ createList.push(Number(key));
314
+ }
315
+ } else {
316
+ destroyList.push(Number(key));
317
+ }
318
+ });
319
+ if (createList.length === 0 && destroyList.length === 0) {
320
+ return false;
321
+ }
322
+ const activeId = Math.max(...stateLayerIdList);
323
+ layerConfigList.forEach((id) => {
324
+ const { router } = this.layerMap[id];
325
+ if (activeId === id) {
326
+ router.unfreeze();
327
+ } else {
328
+ router.freeze();
329
+ }
330
+ });
331
+ destroyList.forEach((id) => {
332
+ const layer = this.layerMap[id];
333
+ if (!layer.destroyed) {
334
+ const { router, config } = layer;
335
+ config.destroy();
336
+ router.destroy();
337
+ router.freeze();
338
+ layer.destroyed = true;
339
+ }
340
+ });
341
+ createList.forEach((id) => {
342
+ const layer = this.layerMap[id];
343
+ if (layer.destroyed) {
344
+ const { router, config } = layer;
345
+ config.mount();
346
+ router.unfreeze();
347
+ layer.destroyed = false;
348
+ }
349
+ });
350
+ this.layerConfigList = stateLayerConfigList;
351
+ return true;
352
+ }
353
+ updateLayerState(route) {
354
+ const layerConfig = this.layerConfigList.find((item) => {
355
+ return item.id === this.layerId;
356
+ });
357
+ if (layerConfig) layerConfig.depth++;
358
+ const stateConfigList = this.layerConfigList.filter(({ id }) => {
359
+ var _a;
360
+ return !((_a = this.layerMap[id]) == null ? void 0 : _a.destroyed);
361
+ });
362
+ const state = {
363
+ ...history.state,
364
+ [StateLayerConfigKey]: stateConfigList
365
+ };
366
+ window.history.replaceState(state, "", route.fullPath);
367
+ }
368
+ /**
369
+ * 新开浏览器窗口的方法,在服务端会调用 push 作为替代
370
+ */
371
+ pushWindow(location2) {
372
+ this.history.pushWindow(location2);
373
+ }
374
+ /**
375
+ * 替换当前浏览器窗口的方法,在服务端会调用 replace 作为替代
376
+ */
377
+ replaceWindow(location2) {
378
+ this.history.replaceWindow(location2);
379
+ }
380
+ /* 前往特定路由历史记录的方法,可以在历史记录前后移动 */
381
+ go(delta = 0) {
382
+ this.history.go(delta);
383
+ }
384
+ /* 路由历史记录前进方法 */
385
+ forward() {
386
+ this.history.forward();
387
+ }
388
+ /* 路由历史记录后退方法 */
389
+ back() {
390
+ this.history.back();
391
+ }
392
+ /* 根据获取当前所有活跃的路由Record对象 */
393
+ getRoutes() {
394
+ return this.matcher.getRoutes();
395
+ }
396
+ }
397
+ export function createRouter(options) {
398
+ return new Router(options);
399
+ }
@@ -0,0 +1 @@
1
+ export { Tasks, createTasks } from './task';
@@ -0,0 +1 @@
1
+ export { Tasks, createTasks } from "./task.mjs";
@@ -0,0 +1,30 @@
1
+ import type { Awaitable } from '../types';
2
+ /**
3
+ * 创建可操作的任务队列
4
+ */
5
+ type func = (...args: any) => any;
6
+ /**
7
+ * 任务状态
8
+ */
9
+ export declare enum TaskStatus {
10
+ INITIAL = "initial",
11
+ RUNNING = "running",
12
+ FINISHED = "finished",
13
+ ERROR = "error",
14
+ ABORTED = "aborted"
15
+ }
16
+ export declare class Tasks<T extends func = func> {
17
+ protected handlers: T[];
18
+ add(handler: T | T[]): void;
19
+ reset(): void;
20
+ get list(): T[];
21
+ get length(): number;
22
+ status: TaskStatus;
23
+ run({ cb, final }?: {
24
+ cb?: (res: Awaited<ReturnType<T>>) => Awaitable<void>;
25
+ final?: () => Awaitable<void>;
26
+ }): Promise<void>;
27
+ abort(): void;
28
+ }
29
+ export declare function createTasks<T extends func = func>(): Tasks<T>;
30
+ export {};
@@ -0,0 +1,66 @@
1
+ import { warn } from "../utils/index.mjs";
2
+ export var TaskStatus = /* @__PURE__ */ ((TaskStatus2) => {
3
+ TaskStatus2["INITIAL"] = "initial";
4
+ TaskStatus2["RUNNING"] = "running";
5
+ TaskStatus2["FINISHED"] = "finished";
6
+ TaskStatus2["ERROR"] = "error";
7
+ TaskStatus2["ABORTED"] = "aborted";
8
+ return TaskStatus2;
9
+ })(TaskStatus || {});
10
+ export class Tasks {
11
+ handlers = [];
12
+ add(handler) {
13
+ const params = handler instanceof Array ? handler : [handler];
14
+ this.handlers.push(...params);
15
+ }
16
+ reset() {
17
+ this.handlers = [];
18
+ }
19
+ get list() {
20
+ return this.handlers;
21
+ }
22
+ get length() {
23
+ return this.handlers.length;
24
+ }
25
+ status = "initial" /* INITIAL */;
26
+ async run({
27
+ cb,
28
+ final
29
+ } = {}) {
30
+ if (this.status !== "initial") {
31
+ if (process.env.NODE_ENV !== "production") {
32
+ warn(`task start failed in status ${this.status}`);
33
+ }
34
+ return;
35
+ }
36
+ this.status = "running" /* RUNNING */;
37
+ for await (const handler of this.list) {
38
+ if (this.status === "aborted" /* ABORTED */) {
39
+ return;
40
+ }
41
+ if (typeof handler === "function") {
42
+ try {
43
+ const res = await handler();
44
+ cb && await cb(res);
45
+ } catch (error) {
46
+ warn("task error:", error);
47
+ this.status = "error" /* ERROR */;
48
+ }
49
+ } else {
50
+ warn("task is not a function", handler);
51
+ }
52
+ }
53
+ if (this.status !== "running" /* RUNNING */) return;
54
+ final && await final();
55
+ this.status = "finished" /* FINISHED */;
56
+ }
57
+ abort() {
58
+ if (process.env.NODE_ENV !== "production" && this.status === "running" /* RUNNING */) {
59
+ warn("abort task when task is running");
60
+ }
61
+ this.status = "aborted" /* ABORTED */;
62
+ }
63
+ }
64
+ export function createTasks() {
65
+ return new Tasks();
66
+ }
@@ -0,0 +1,5 @@
1
+ /**
2
+ * 在新窗口打开页面,如果被拦截,则会降级到当前窗口打开
3
+ * @param url 打开的地址
4
+ */
5
+ export declare function openWindow(url: string, target?: string): void;
@@ -0,0 +1,10 @@
1
+ export function openWindow(url, target) {
2
+ try {
3
+ const newWindow = window.open(url, target);
4
+ if (!newWindow) {
5
+ location.href = url;
6
+ }
7
+ } catch (e) {
8
+ location.href = url;
9
+ }
10
+ }
@@ -0,0 +1,48 @@
1
+ export declare const PLUS_RE: RegExp;
2
+ /**
3
+ * Encode characters that need to be encoded on the hash section of the URL.
4
+ *
5
+ * @param text - string to encode
6
+ * @returns encoded string
7
+ */
8
+ export declare function encodeHash(text: string): string;
9
+ /**
10
+ * Encode characters that need to be encoded query values on the query
11
+ * section of the URL.
12
+ *
13
+ * @param text - string to encode
14
+ * @returns encoded string
15
+ */
16
+ export declare function encodeQueryValue(text: string | number): string;
17
+ /**
18
+ * Like `encodeQueryValue` but also encodes the `=` character.
19
+ *
20
+ * @param text - string to encode
21
+ */
22
+ export declare function encodeQueryKey(text: string | number): string;
23
+ /**
24
+ * Encode characters that need to be encoded on the path section of the URL.
25
+ *
26
+ * @param text - string to encode
27
+ * @returns encoded string
28
+ */
29
+ export declare function encodePath(text: string | number): string;
30
+ /**
31
+ * Encode characters that need to be encoded on the path section of the URL as a
32
+ * param. This function encodes everything {@link encodePath} does plus the
33
+ * slash (`/`) character. If `text` is `null` or `undefined`, returns an empty
34
+ * string instead.
35
+ *
36
+ * @param text - string to encode
37
+ * @returns encoded string
38
+ */
39
+ export declare function encodeParam(text: string | number | null | undefined): string;
40
+ /**
41
+ * Decode text using `decodeURIComponent`. Returns the original text if it
42
+ * fails.
43
+ *
44
+ * @param text - string to decode
45
+ * @returns decoded string
46
+ */
47
+ export declare function decode(text: string | number): string;
48
+ export declare function decodeQuery(text: string): string;
@@ -0,0 +1,44 @@
1
+ import { warn } from "./warn.mjs";
2
+ const HASH_RE = /#/g;
3
+ const AMPERSAND_RE = /&/g;
4
+ const SLASH_RE = /\//g;
5
+ const EQUAL_RE = /=/g;
6
+ const IM_RE = /\?/g;
7
+ export const PLUS_RE = /\+/g;
8
+ const ENC_BRACKET_OPEN_RE = /%5B/g;
9
+ const ENC_BRACKET_CLOSE_RE = /%5D/g;
10
+ const ENC_CARET_RE = /%5E/g;
11
+ const ENC_BACKTICK_RE = /%60/g;
12
+ const ENC_CURLY_OPEN_RE = /%7B/g;
13
+ const ENC_PIPE_RE = /%7C/g;
14
+ const ENC_CURLY_CLOSE_RE = /%7D/g;
15
+ const ENC_SPACE_RE = /%20/g;
16
+ function commonEncode(text) {
17
+ return encodeURIComponent("" + text).replace(ENC_PIPE_RE, "|").replace(ENC_BRACKET_OPEN_RE, "[").replace(ENC_BRACKET_CLOSE_RE, "]");
18
+ }
19
+ export function encodeHash(text) {
20
+ return commonEncode(text).replace(ENC_CURLY_OPEN_RE, "{").replace(ENC_CURLY_CLOSE_RE, "}").replace(ENC_CARET_RE, "^");
21
+ }
22
+ export function encodeQueryValue(text) {
23
+ return commonEncode(text).replace(PLUS_RE, "%2B").replace(ENC_SPACE_RE, "+").replace(HASH_RE, "%23").replace(AMPERSAND_RE, "%26").replace(ENC_BACKTICK_RE, "`").replace(ENC_CURLY_OPEN_RE, "{").replace(ENC_CURLY_CLOSE_RE, "}").replace(ENC_CARET_RE, "^");
24
+ }
25
+ export function encodeQueryKey(text) {
26
+ return encodeQueryValue(text).replace(EQUAL_RE, "%3D");
27
+ }
28
+ export function encodePath(text) {
29
+ return commonEncode(text).replace(HASH_RE, "%23").replace(IM_RE, "%3F");
30
+ }
31
+ export function encodeParam(text) {
32
+ return text == null ? "" : encodePath(text).replace(SLASH_RE, "%2F");
33
+ }
34
+ export function decode(text) {
35
+ try {
36
+ return decodeURIComponent("" + text);
37
+ } catch (err) {
38
+ warn(`Error decoding "${text}". Using original value`);
39
+ }
40
+ return "" + text;
41
+ }
42
+ export function decodeQuery(text) {
43
+ return decode(text.replace(PLUS_RE, " "));
44
+ }
@@ -0,0 +1,9 @@
1
+ import type { RouteRecord } from '../types';
2
+ /**
3
+ * 判断是否是同一个路由
4
+ */
5
+ export declare function isSameRoute(from: RouteRecord, to: RouteRecord): any;
6
+ /**
7
+ * 判断是否是全等的路由: 路径完全相同
8
+ */
9
+ export declare function isEqualRoute(from: RouteRecord, to: RouteRecord): boolean;
@@ -0,0 +1,12 @@
1
+ export function isSameRoute(from, to) {
2
+ return from.matched.length === to.matched.length && from.matched.every((record, i) => record === to.matched[i]);
3
+ }
4
+ export function isEqualRoute(from, to) {
5
+ return (
6
+ // 这里不仅仅判断了前后的path是否一致
7
+ // 同时判断了匹配路由对象的个数
8
+ // 这是因为在首次初始化时 this.current 的值为 { path:'/',matched:[] }
9
+ // 假如我们打开页面同样为 / 路径时,此时如果单纯判断path那么就会造成无法渲染
10
+ from.fullPath === to.fullPath && from.matched.length === to.matched.length
11
+ );
12
+ }
@@ -0,0 +1,7 @@
1
+ export { regexDomain, normalizePath, parsePath, stringifyPath, normalizeLocation, isPathWithProtocolOrDomain } from './path';
2
+ export { isESModule, inBrowser } from './utils';
3
+ export { warn } from './warn';
4
+ export { isSameRoute, isEqualRoute } from './guards';
5
+ export { computeScrollPosition, scrollToPosition, saveScrollPosition, getSavedScrollPosition, getKeepScrollPosition } from './scroll';
6
+ export { openWindow } from './bom';
7
+ export { encodeHash, encodeParam, encodePath, encodeQueryKey, encodeQueryValue, decode } from './encoding';
@@ -0,0 +1,27 @@
1
+ export {
2
+ regexDomain,
3
+ normalizePath,
4
+ parsePath,
5
+ stringifyPath,
6
+ normalizeLocation,
7
+ isPathWithProtocolOrDomain
8
+ } from "./path.mjs";
9
+ export { isESModule, inBrowser } from "./utils.mjs";
10
+ export { warn } from "./warn.mjs";
11
+ export { isSameRoute, isEqualRoute } from "./guards.mjs";
12
+ export {
13
+ computeScrollPosition,
14
+ scrollToPosition,
15
+ saveScrollPosition,
16
+ getSavedScrollPosition,
17
+ getKeepScrollPosition
18
+ } from "./scroll.mjs";
19
+ export { openWindow } from "./bom.mjs";
20
+ export {
21
+ encodeHash,
22
+ encodeParam,
23
+ encodePath,
24
+ encodeQueryKey,
25
+ encodeQueryValue,
26
+ decode
27
+ } from "./encoding.mjs";