|
|
@@ -1,71 +1,30 @@
|
|
|
-import { reactive, toRefs, readonly } from 'vue'
|
|
|
+import { ref, toRefs, readonly } from 'vue'
|
|
|
import { createRouter, RouterOptions, RouteRecordRaw, RouteLocationNormalized } from 'vue-router'
|
|
|
|
|
|
-interface RouterState {
|
|
|
- historyStack: RouteLocationNormalized[]; // 已访问的路由列表
|
|
|
+interface HistoryState {
|
|
|
+ historyStacks: RouteLocationNormalized[]; // 已访问的路由列表
|
|
|
excludeName: string[]; // 不缓存的组件名称
|
|
|
actionName: '' | 'push' | 'replace' | 'forward' | 'back'; // 当前路由动作
|
|
|
transitionName: '' | 'slide-right' | 'slide-left'; // 前进后退动画
|
|
|
}
|
|
|
|
|
|
export default new (class {
|
|
|
- private state = reactive<RouterState>({
|
|
|
- historyStack: [],
|
|
|
+ private _state = ref<HistoryState>({
|
|
|
+ historyStacks: [],
|
|
|
excludeName: [],
|
|
|
actionName: '',
|
|
|
transitionName: '',
|
|
|
})
|
|
|
|
|
|
- /**
|
|
|
- * 处理路由历史状态
|
|
|
- * @param route
|
|
|
- */
|
|
|
- private handleState(route: RouteLocationNormalized) {
|
|
|
- this.state.excludeName = [];
|
|
|
- const { historyStack, actionName } = this.state;
|
|
|
-
|
|
|
- // 如果是替换动作,必定是前进
|
|
|
- if (actionName === 'replace') {
|
|
|
- const lastIndex = historyStack.length - 1;
|
|
|
- const lastPage = historyStack[lastIndex];
|
|
|
-
|
|
|
- this.state.excludeName.push(lastPage.name as string);
|
|
|
- this.state.historyStack.fill(route, lastIndex); // 替换最后一个位置
|
|
|
- this.state.transitionName = 'slide-left'; // 前进动画
|
|
|
- } else {
|
|
|
- // 倒序查找路由所在的位置
|
|
|
- const index = (() => {
|
|
|
- for (let i = historyStack.length - 1; i >= 0; i--) {
|
|
|
- if (historyStack[i].fullPath == route.fullPath) {
|
|
|
- return i;
|
|
|
- }
|
|
|
- }
|
|
|
- return -1;
|
|
|
- })();
|
|
|
+ /** 只读状态 */
|
|
|
+ state;
|
|
|
|
|
|
- if (index > -1) {
|
|
|
- if (actionName === 'push') {
|
|
|
- this.state.historyStack.push(route);
|
|
|
- this.state.transitionName = 'slide-left'; //前进动画
|
|
|
- } else {
|
|
|
- if (historyStack.length > 1) {
|
|
|
- const i = index + 1;
|
|
|
- const n = historyStack.length - i;
|
|
|
-
|
|
|
- this.state.excludeName = historyStack.map((e) => e.name).slice(-n) as string[]; // 返回数组最后位置开始的n个元素
|
|
|
- this.state.historyStack.splice(i, n); // 从i位置开始删除后面所有元素(包括i)
|
|
|
- }
|
|
|
- this.state.transitionName = 'slide-right'; //后退动画
|
|
|
- }
|
|
|
- } else {
|
|
|
- historyStack.push(route);
|
|
|
- if (historyStack.length > 1) {
|
|
|
- this.state.transitionName = 'slide-left'; // 前进动画
|
|
|
- }
|
|
|
- }
|
|
|
+ constructor() {
|
|
|
+ const state = sessionStorage.getItem('historyState');
|
|
|
+ if (state) {
|
|
|
+ this._state.value = JSON.parse(state);
|
|
|
}
|
|
|
-
|
|
|
- this.state.actionName = '';
|
|
|
+ this.state = readonly(toRefs(this._state.value));
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
@@ -76,54 +35,107 @@ export default new (class {
|
|
|
create(options: RouterOptions) {
|
|
|
const router = createRouter(options);
|
|
|
const { push, replace, go, forward, back } = router;
|
|
|
+ const { actionName } = toRefs(this._state.value);
|
|
|
|
|
|
// 添加
|
|
|
router.push = (to: RouteRecordRaw) => {
|
|
|
- this.state.actionName = 'push';
|
|
|
+ actionName.value = 'push';
|
|
|
return push(to);
|
|
|
}
|
|
|
|
|
|
// 替换
|
|
|
router.replace = (to: RouteRecordRaw) => {
|
|
|
- this.state.actionName = 'replace';
|
|
|
+ actionName.value = 'replace';
|
|
|
return replace(to);
|
|
|
}
|
|
|
|
|
|
// 前进后退
|
|
|
router.go = (delta: number) => {
|
|
|
if (delta > 0) {
|
|
|
- this.state.actionName = 'forward';
|
|
|
+ actionName.value = 'forward';
|
|
|
}
|
|
|
if (delta < 0) {
|
|
|
- this.state.actionName = 'back';
|
|
|
+ actionName.value = 'back';
|
|
|
}
|
|
|
go(delta);
|
|
|
}
|
|
|
|
|
|
// 前进
|
|
|
router.forward = () => {
|
|
|
- this.state.actionName = 'forward';
|
|
|
+ actionName.value = 'forward';
|
|
|
forward();
|
|
|
}
|
|
|
|
|
|
// 后退
|
|
|
router.back = () => {
|
|
|
- this.state.actionName = 'back';
|
|
|
+ actionName.value = 'back';
|
|
|
back();
|
|
|
}
|
|
|
|
|
|
router.beforeResolve((to) => {
|
|
|
- this.handleState(to);
|
|
|
+ this.add(to);
|
|
|
})
|
|
|
|
|
|
return router;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * 获取路由历史状态(只读)
|
|
|
- * @returns
|
|
|
+ * 添加历史记录
|
|
|
+ * @param route
|
|
|
*/
|
|
|
- getState() {
|
|
|
- return toRefs(readonly(this.state));
|
|
|
+ private add(route: RouteLocationNormalized) {
|
|
|
+ const { historyStacks, excludeName, actionName, transitionName } = toRefs(this._state.value);
|
|
|
+ excludeName.value = [];
|
|
|
+
|
|
|
+ // 如果是替换动作,必定是前进
|
|
|
+ if (actionName.value === 'replace') {
|
|
|
+ const lastIndex = historyStacks.value.length - 1;
|
|
|
+ const lastPage = historyStacks.value[lastIndex];
|
|
|
+
|
|
|
+ if (lastPage) {
|
|
|
+ excludeName.value.push(lastPage.name as string);
|
|
|
+ historyStacks.value[lastIndex] = route; // 更新最后一条记录
|
|
|
+ } else {
|
|
|
+ historyStacks.value.push(route);
|
|
|
+ }
|
|
|
+ transitionName.value = 'slide-left'; // 前进动画
|
|
|
+ } else {
|
|
|
+ // 倒序查找路由所在的位置
|
|
|
+ const index = (() => {
|
|
|
+ for (let i = historyStacks.value.length - 1; i >= 0; i--) {
|
|
|
+ if (historyStacks.value[i].fullPath == route.fullPath) {
|
|
|
+ return i;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return -1;
|
|
|
+ })();
|
|
|
+
|
|
|
+ if (index > -1) {
|
|
|
+ if (actionName.value === 'push') {
|
|
|
+ historyStacks.value.push(route);
|
|
|
+ transitionName.value = 'slide-left'; //前进动画
|
|
|
+ } else {
|
|
|
+ if (historyStacks.value.length > 1) {
|
|
|
+ const i = index + 1;
|
|
|
+ const n = historyStacks.value.length - i;
|
|
|
+
|
|
|
+ excludeName.value = historyStacks.value.map((e) => e.name).slice(-n) as string[]; // 返回数组最后位置开始的n个元素
|
|
|
+ historyStacks.value.splice(i, n); // 从i位置开始删除后面所有元素(包括i)
|
|
|
+ }
|
|
|
+ transitionName.value = 'slide-right'; //后退动画
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ // 忽略重定向的页面
|
|
|
+ if (!route.redirectedFrom) {
|
|
|
+ historyStacks.value.push(route);
|
|
|
+ if (historyStacks.value.length > 1) {
|
|
|
+ transitionName.value = 'slide-left'; // 前进动画
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ actionName.value = '';
|
|
|
+ sessionStorage.setItem('historyState', JSON.stringify(this._state.value));
|
|
|
}
|
|
|
})
|