animateRouter.ts 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159
  1. import { ref, toRefs, readonly } from 'vue'
  2. import { createRouter, RouterOptions, RouteRecordRaw, RouteLocationNormalized } from 'vue-router'
  3. interface HistoryState {
  4. history: RouteLocationNormalized[]; // 已访问的路由列表
  5. excludeViews: string[]; // 不缓存的页面
  6. actionName: '' | 'push' | 'replace' | 'forward' | 'back'; // 当前路由动作
  7. transitionName: '' | 'route-out' | 'route-in'; // 前进后退动画
  8. goStep: number; // 前进后退步数
  9. }
  10. export default new (class {
  11. private storageKey = 'history_mobile';
  12. private _state = ref<HistoryState>({
  13. history: [],
  14. excludeViews: [],
  15. actionName: '',
  16. transitionName: '',
  17. goStep: 0,
  18. })
  19. /** 只读状态 */
  20. state;
  21. constructor() {
  22. const state = sessionStorage.getItem(this.storageKey);
  23. if (state) {
  24. this._state.value = JSON.parse(state);
  25. }
  26. this.state = readonly(toRefs(this._state.value));
  27. }
  28. /**
  29. * 创建路由
  30. * @param options
  31. * @returns
  32. */
  33. create = (options: RouterOptions) => {
  34. const router = createRouter(options);
  35. const { push, replace, go, forward, back } = router;
  36. const { actionName, goStep } = toRefs(this._state.value);
  37. // 添加
  38. router.push = (to: RouteRecordRaw) => {
  39. actionName.value = 'push';
  40. return push(to);
  41. }
  42. // 替换
  43. router.replace = (to: RouteRecordRaw) => {
  44. actionName.value = 'replace';
  45. return replace(to);
  46. }
  47. // 前进后退
  48. router.go = (delta: number) => {
  49. goStep.value = delta;
  50. if (delta > 0) {
  51. actionName.value = 'forward';
  52. }
  53. if (delta < 0) {
  54. actionName.value = 'back';
  55. }
  56. go(delta);
  57. }
  58. // 前进
  59. router.forward = () => {
  60. actionName.value = 'forward';
  61. forward();
  62. }
  63. // 后退
  64. router.back = () => {
  65. actionName.value = 'back';
  66. back();
  67. }
  68. router.beforeResolve((to) => {
  69. this.addHistory(to);
  70. })
  71. router.afterEach(() => {
  72. const { excludeViews } = toRefs(this._state.value);
  73. excludeViews.value = [];
  74. })
  75. return router;
  76. }
  77. /**
  78. * 添加历史记录
  79. * @param route
  80. */
  81. private addHistory = (route: RouteLocationNormalized) => {
  82. const { history, excludeViews, actionName, transitionName, goStep } = toRefs(this._state.value);
  83. // 如果是替换动作,必定是前进
  84. if (actionName.value === 'replace') {
  85. const lastIndex = history.value.length - 1;
  86. const lastView = history.value[lastIndex];
  87. if (lastView) {
  88. excludeViews.value.push(lastView.name as string);
  89. history.value[lastIndex] = route; // 更新最后一条记录
  90. } else {
  91. history.value.push(route);
  92. }
  93. transitionName.value = 'route-in'; // 前进动画
  94. } else {
  95. // 倒序查找路由所在的位置
  96. const index = (() => {
  97. for (let i = history.value.length - 1; i >= 0; i--) {
  98. if (history.value[i].fullPath === route.fullPath) {
  99. return i;
  100. }
  101. }
  102. return -1;
  103. })();
  104. if (index > -1) {
  105. if (actionName.value === 'push') {
  106. history.value.push(route);
  107. transitionName.value = 'route-in'; //前进动画
  108. } else {
  109. if (history.value.length > 1) {
  110. const i = index + 1;
  111. const n = history.value.length - i;
  112. excludeViews.value = history.value.map((e) => e.name).slice(-n) as string[]; // 返回数组最后位置开始的n个元素
  113. history.value.splice(i, n); // 从i位置开始删除后面所有元素(包括i)
  114. }
  115. transitionName.value = 'route-out'; //后退动画
  116. }
  117. } else {
  118. if (goStep.value < 0) {
  119. const start = history.value.length + goStep.value
  120. if (start) {
  121. history.value.splice(start)
  122. }
  123. }
  124. // 忽略重定向的页面
  125. if (route.redirectedFrom) {
  126. transitionName.value = 'route-in'; // 前进动画
  127. } else {
  128. history.value.push(route);
  129. if (history.value.length > 1) {
  130. transitionName.value = 'route-in'; // 前进动画
  131. }
  132. }
  133. }
  134. }
  135. actionName.value = '';
  136. goStep.value = 0
  137. sessionStorage.setItem(this.storageKey, JSON.stringify(this._state.value));
  138. }
  139. })