|
|
@@ -1,38 +1,47 @@
|
|
|
-import { ref, toRefs, readonly } from 'vue'
|
|
|
+import { ref, toRefs } from 'vue'
|
|
|
import { createRouter, RouterOptions, RouteRecordRaw, RouteLocationNormalized } from 'vue-router'
|
|
|
|
|
|
+interface historyRoute {
|
|
|
+ name: string;
|
|
|
+ fullPath: string;
|
|
|
+}
|
|
|
+
|
|
|
interface HistoryState {
|
|
|
- history: RouteLocationNormalized[]; // 已访问的路由列表
|
|
|
- excludeViews: string[]; // 不缓存的页面
|
|
|
+ historyRoutes: historyRoute[]; // 历史路由列表
|
|
|
+ excludeViews: string[]; // 不缓存的视图
|
|
|
actionName: '' | 'push' | 'replace' | 'forward' | 'back'; // 当前路由动作
|
|
|
transitionName: '' | 'route-out' | 'route-in'; // 前进后退动画
|
|
|
goStep: number; // 前进后退步数
|
|
|
}
|
|
|
|
|
|
export default new (class {
|
|
|
- private storageKey = 'history_mobile';
|
|
|
+ private storageKey = 'history_mobile'
|
|
|
|
|
|
- private _state = ref<HistoryState>({
|
|
|
- history: [],
|
|
|
+ private state = ref<HistoryState>({
|
|
|
+ historyRoutes: [],
|
|
|
excludeViews: [],
|
|
|
actionName: '',
|
|
|
transitionName: '',
|
|
|
- goStep: 0,
|
|
|
+ goStep: 0
|
|
|
})
|
|
|
|
|
|
- /** 只读状态 */
|
|
|
- state;
|
|
|
-
|
|
|
constructor() {
|
|
|
- const state = sessionStorage.getItem(this.storageKey);
|
|
|
+ const state = sessionStorage.getItem(this.storageKey)
|
|
|
if (state) {
|
|
|
// 合并赋值,防止 sessionStorage 获取的值有问题
|
|
|
- this._state.value = {
|
|
|
- ...this._state.value,
|
|
|
+ this.state.value = {
|
|
|
+ ...this.state.value,
|
|
|
...JSON.parse(state)
|
|
|
- };
|
|
|
+ }
|
|
|
}
|
|
|
- this.state = readonly(toRefs(this._state.value));
|
|
|
+ }
|
|
|
+
|
|
|
+ getState() {
|
|
|
+ return this.state.value
|
|
|
+ }
|
|
|
+
|
|
|
+ getStateRef() {
|
|
|
+ return toRefs(this.state.value)
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
@@ -41,56 +50,55 @@ export default new (class {
|
|
|
* @returns
|
|
|
*/
|
|
|
create = (options: RouterOptions) => {
|
|
|
- const router = createRouter(options);
|
|
|
- const { push, replace, go, forward, back } = router;
|
|
|
- const { actionName, goStep } = toRefs(this._state.value);
|
|
|
+ const router = createRouter(options)
|
|
|
+ const { push, replace, go, forward, back } = router
|
|
|
+ const { excludeViews, actionName, goStep } = this.getStateRef()
|
|
|
|
|
|
// 添加
|
|
|
router.push = (to: RouteRecordRaw) => {
|
|
|
- actionName.value = 'push';
|
|
|
- return push(to);
|
|
|
+ actionName.value = 'push'
|
|
|
+ return push(to)
|
|
|
}
|
|
|
|
|
|
// 替换
|
|
|
router.replace = (to: RouteRecordRaw) => {
|
|
|
- actionName.value = 'replace';
|
|
|
- return replace(to);
|
|
|
+ actionName.value = 'replace'
|
|
|
+ return replace(to)
|
|
|
}
|
|
|
|
|
|
// 前进后退
|
|
|
router.go = (delta: number) => {
|
|
|
- goStep.value = delta;
|
|
|
+ goStep.value = delta
|
|
|
if (delta > 0) {
|
|
|
- actionName.value = 'forward';
|
|
|
+ actionName.value = 'forward'
|
|
|
}
|
|
|
if (delta < 0) {
|
|
|
- actionName.value = 'back';
|
|
|
+ actionName.value = 'back'
|
|
|
}
|
|
|
- go(delta);
|
|
|
+ go(delta)
|
|
|
}
|
|
|
|
|
|
// 前进
|
|
|
router.forward = () => {
|
|
|
- actionName.value = 'forward';
|
|
|
- forward();
|
|
|
+ actionName.value = 'forward'
|
|
|
+ forward()
|
|
|
}
|
|
|
|
|
|
// 后退
|
|
|
router.back = () => {
|
|
|
- actionName.value = 'back';
|
|
|
- back();
|
|
|
+ actionName.value = 'back'
|
|
|
+ back()
|
|
|
}
|
|
|
|
|
|
router.beforeResolve((to) => {
|
|
|
- this.addHistory(to);
|
|
|
+ this.addHistory(to)
|
|
|
})
|
|
|
|
|
|
router.afterEach(() => {
|
|
|
- const { excludeViews } = toRefs(this._state.value);
|
|
|
- excludeViews.value = [];
|
|
|
+ excludeViews.value = []
|
|
|
})
|
|
|
|
|
|
- return router;
|
|
|
+ return router
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
@@ -98,81 +106,86 @@ export default new (class {
|
|
|
* @param route
|
|
|
*/
|
|
|
private addHistory = (route: RouteLocationNormalized) => {
|
|
|
- const { history, excludeViews, actionName, transitionName, goStep } = toRefs(this._state.value);
|
|
|
+ const { historyRoutes, excludeViews, actionName, transitionName, goStep } = this.getStateRef()
|
|
|
+ const newRoute = {
|
|
|
+ name: route.name as string,
|
|
|
+ fullPath: route.fullPath
|
|
|
+ }
|
|
|
|
|
|
// 如果是替换动作,必定是前进
|
|
|
if (actionName.value === 'replace') {
|
|
|
- const lastIndex = history.value.length - 1;
|
|
|
- const lastView = history.value[lastIndex];
|
|
|
+ const lastIndex = historyRoutes.value.length - 1
|
|
|
+ const lastView = historyRoutes.value[lastIndex]
|
|
|
|
|
|
if (lastView) {
|
|
|
- excludeViews.value.push(lastView.name as string);
|
|
|
- history.value[lastIndex] = route; // 更新最后一条记录
|
|
|
+ excludeViews.value.push(lastView.name as string)
|
|
|
+ historyRoutes.value[lastIndex] = newRoute // 更新最后一条记录
|
|
|
} else {
|
|
|
- history.value.push(route);
|
|
|
+ historyRoutes.value.push(newRoute)
|
|
|
}
|
|
|
- transitionName.value = 'route-in'; // 前进动画
|
|
|
+
|
|
|
+ transitionName.value = 'route-in' // 前进动画
|
|
|
} else {
|
|
|
// 倒序查找路由所在的位置
|
|
|
const index = (() => {
|
|
|
- for (let i = history.value.length - 1; i >= 0; i--) {
|
|
|
- if (history.value[i].fullPath === route.fullPath) {
|
|
|
- return i;
|
|
|
+ for (let i = historyRoutes.value.length - 1; i >= 0; i--) {
|
|
|
+ if (historyRoutes.value[i].fullPath === route.fullPath) {
|
|
|
+ return i
|
|
|
}
|
|
|
}
|
|
|
- return -1;
|
|
|
- })();
|
|
|
+ return -1
|
|
|
+ })()
|
|
|
|
|
|
if (index > -1) {
|
|
|
if (actionName.value === 'push') {
|
|
|
- history.value.push(route);
|
|
|
- transitionName.value = 'route-in'; //前进动画
|
|
|
+ historyRoutes.value.push(newRoute)
|
|
|
+ transitionName.value = 'route-in' //前进动画
|
|
|
} else {
|
|
|
- if (history.value.length > 1) {
|
|
|
- const i = index + 1;
|
|
|
- const n = history.value.length - i;
|
|
|
+ if (historyRoutes.value.length > 1) {
|
|
|
+ const i = index + 1
|
|
|
+ const n = historyRoutes.value.length - i
|
|
|
|
|
|
- excludeViews.value = history.value.map((e) => e.name).slice(-n) as string[]; // 返回数组最后位置开始的n个元素
|
|
|
- history.value.splice(i, n); // 从i位置开始删除后面所有元素(包括i)
|
|
|
+ excludeViews.value = historyRoutes.value.map((e) => e.name).slice(-n) // 返回数组最后位置开始的n个元素
|
|
|
+ historyRoutes.value.splice(i, n) // 从i位置开始删除后面所有元素(包括i)
|
|
|
}
|
|
|
- transitionName.value = 'route-out'; //后退动画
|
|
|
+ transitionName.value = 'route-out' //后退动画
|
|
|
}
|
|
|
} else {
|
|
|
if (goStep.value < 0) {
|
|
|
- const start = history.value.length + goStep.value
|
|
|
+ const start = historyRoutes.value.length + goStep.value
|
|
|
if (start) {
|
|
|
- history.value.splice(start)
|
|
|
+ historyRoutes.value.splice(start)
|
|
|
}
|
|
|
}
|
|
|
// 忽略重定向的页面
|
|
|
if (route.redirectedFrom) {
|
|
|
- transitionName.value = 'route-in'; // 前进动画
|
|
|
+ transitionName.value = 'route-in' // 前进动画
|
|
|
} else {
|
|
|
- history.value.push(route);
|
|
|
- if (history.value.length > 1) {
|
|
|
- transitionName.value = 'route-in'; // 前进动画
|
|
|
+ historyRoutes.value.push(newRoute)
|
|
|
+ if (historyRoutes.value.length > 1) {
|
|
|
+ transitionName.value = 'route-in' // 前进动画
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- actionName.value = '';
|
|
|
+ actionName.value = ''
|
|
|
goStep.value = 0
|
|
|
|
|
|
// 处理对象循环引用
|
|
|
- const getCircularReplacer = () => {
|
|
|
- const seen = new WeakSet()
|
|
|
- return (key: string, value: unknown) => {
|
|
|
- if (typeof value === 'object' && value !== null) {
|
|
|
- if (seen.has(value)) {
|
|
|
- return
|
|
|
- }
|
|
|
- seen.add(value)
|
|
|
- }
|
|
|
- return value
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- sessionStorage.setItem(this.storageKey, JSON.stringify(this._state.value, getCircularReplacer()))
|
|
|
+ // const getCircularReplacer = () => {
|
|
|
+ // const seen = new WeakSet()
|
|
|
+ // return (key: string, value: unknown) => {
|
|
|
+ // if (typeof value === 'object' && value !== null) {
|
|
|
+ // if (seen.has(value)) {
|
|
|
+ // return
|
|
|
+ // }
|
|
|
+ // seen.add(value)
|
|
|
+ // }
|
|
|
+ // return value
|
|
|
+ // }
|
|
|
+ // }
|
|
|
+
|
|
|
+ sessionStorage.setItem(this.storageKey, JSON.stringify(this.state.value))
|
|
|
}
|
|
|
})
|