深圳大鹏生态监控平台(Vue3 大屏应用)封装记录历史路由的方法

目录

一. utils/router-history/index.ts 封装记录路由的具体方法

1.定义 路由接口、路由数组、记录路由类

2.定义记录路由类

二. store/index.ts 用 vuex 实现路由存储

1.初始化 stroe/index.ts

2.通用状态具体编写

三. 使用 vuex 记录路由

1.home.vue 的基本构成

2.在 main.ts 中,引入 vuex 相关内容 store/index.ts

3.在 home.vue 中,引入 vuex 相关内容,编写路由切换规则

4.在 vue页面 中,引入 vuex 相关内容,编写路由切换规则


封装原因

点击左右侧第一层页面,进入了更深层的页面;

这时,如果点击了地图点位,会有弹框出现在右侧页面;

如果点击关闭弹框,应该出现之前的更深层的页面,而不是第一层页面;

因此需要 记忆路由

一. utils/router-history/index.ts 封装记录路由的具体方法

1.定义 路由接口、路由数组、记录路由类

路由接口:路由名称必填,路由参数选填(键值对、null、undefined)

  • export interface RouterData {
      name: string; 
      params?: {
        [key: string]: any
      } | null | undefined;
    }
     

路由数组类型:export type RouterStackData = RouterData[];

记录路由类:export class RouterHistory {}

2.定义记录路由类

私有路由栈:private routerStack: RouterStackData = [];

记录路由类的构造函数:可以传入参数,或者默认为空数组

  •   constructor(parameters?: RouterStackData) {
        this.routerStack = parameters || [];
      }

2.1 判断两个对象是否相等

@memberof:属于哪个类

判断方式:对比两个路由对象的 JSON格式的 名字

注意:要定义成 私有静态 的方法

  /**
   * @description 判断两个对象是否相等
   * @private
   * @param routerA 对象甲
   * @param routerB 对象乙
   * @returns {boolean} 等吗
   * @memberof RouterHistory
   */
  private static isEqual(routerA: RouterData, routerB: RouterData): boolean {
    return JSON.stringify(routerA.name) === JSON.stringify(routerB.name);
  }

 

2.2 判断路由是否可以进栈

如果当前路由栈为空,就可以进栈

调用当前类 RouterHistory 中,前面定义的方法 isEqual()

判断即将进栈的路由,是否等于路由栈中的最后一个路由

二者不等即可防止重复进栈

  /**
   * @description 判断路由是否可以进栈
   * @private
   * @param route 路由
   * @returns {boolean} 可以吗
   * @memberof RouterHistory
   */
  private canPush(route: RouterData): boolean {
    if (this.routerStack.length === 0) {
      return true;
    }
    // 防止路由重复入栈
    return !RouterHistory.isEqual(this.routerStack[this.routerStack.length - 1], route);
  }

 

2.3 查询路由栈是否存在当前路由

假设当前路由不存在于路由栈,也就是序列号为 index =  -1

遍历路由栈,判断其中的每一项,是否与传入的当前路由一致

一致的话,返回当前路由 在路由栈中的序列号位置【本质上就是数组下标】

不一致的话,说明路由栈中没有当前路由对象,因此返回不存在的序列号 index = -1

  /**
   * @description 查询路由栈是否存在当前路由
   * @private
   * @param route 当前路由
   * @returns {*} 若存在返回序列号,不存在-1
   * @memberof RouterHistory
   */
  private getSameIndex(route: RouterData) {
    let index = -1;
    // eslint-disable-next-line no-return-assign
    this.routerStack.some((item, i) => 
        (RouterHistory.isEqual(item, route) ? index = i : false));
    return index;
  }

 

2.4 路由进栈

如果传入的对象不是路由,或者传入的路由对象不满足进栈条件(和路由栈中最后一个元素相等)

返回 false,禁止路由进栈

获取当前路由栈的元素个数(长度)

当前路由栈不止一个元素时,获取当前传入路由在路由栈中的位置(可能有位置,可能没位置)

  1. 如果当前路由不存在于路由栈,就直接向路由栈中添加当前路由
  2. 如果当前路由存在于路由栈,就执行下面定义的删除当前路由的方法

当前路由栈只有一个元素时,直接执行进栈操作(给路由数组 push 路由对象)

  /**
   * @description 路由进栈
   * @param route 路由
   * @returns {boolean} 成功与否
   * @memberof RouterHistory
   */
  public push(route: RouterData): boolean {
    if (!route || !this.canPush(route)) {
      return false;
    }
    const oldLength = this.routerStack.length;
    // 防止路由循环入栈
    if (oldLength > 1) {
      const index = this.getSameIndex(route);
      if (index === -1) {
        return this.routerStack.push(route) === oldLength + 1;
      }
      return this.pop(index);
    }
    // 正常入栈
    return this.routerStack.push(route) === oldLength + 1;
  }

 

2.5 路由出栈

该方法接受一个参数 index,表示某路由对象在路由栈中的位置

index 可以是存在的,也可以是不存在的,即某路由对象不一定存在于路由栈

如果 index 不存在,也就是该路由对象不存在于路由栈,那就意味着不可以出栈

如果 index 存在,那就删除那个路由所在位置之后的全部路由

  /**
   * @description 路由出栈
   * @param [index=undefined] 指定序号:会弹出指定序号之后所有的路由
   * @returns {boolean} 成功与否
   * @memberof RouterHistory
   */
  public pop(index: number | undefined = undefined): boolean {
    if (index === undefined) {
      return this.routerStack.pop() !== undefined;
    }
    return this.routerStack.splice(index + 1, this.routerStack.length).length > 0;
  }

 

2.6 获取全部路由记录

就是返回当前路由栈数组

  /**
   * @description 获取全部路由记录
   * @returns {RouterStackData} 路由记录
   * @memberof RouterHistory
   */
  public getAll(): RouterStackData {
    return this.routerStack;
  }

 

2.7 获取当前(父级)路由、获取当前(父级)路由序号

获取当前路由:如果路由栈存在内容,就返回最后一个元素,不存在,就返回空,即不存在当前路由

获取当前路由序号:当前路由栈长度 - 1

获取父级内容,就相当于获取路由栈的 倒数第二个元素

  /**
   * @description 获取当前路由
   * @returns {RouterData} 当前路由
   * @memberof RouterHistory
   */
  public getCurrent(): RouterData | null {
    return this.routerStack.length > 0 ? this.routerStack[this.routerStack.length - 1] : null;
  }

  /**
   * @description 获取当前路由序号
   * @returns {number} 序号
   * @memberof RouterHistory
   */
  public getCurrentIndex(): number {
    return this.routerStack.length - 1;
  }

 

二. store/index.ts 用 vuex 实现路由存储

1.初始化 stroe/index.ts

引入相关内容:

  • import { createStore } from 'vuex';
  • import { RouterHistory } from '../utils/router-history/index';

设置路由历史数据:export const SET_ROUTERHISTORY = 'SET_ROUTERHISTORY';

编写通用状态:export default createStore({ });

2.通用状态具体编写

定义左右侧记录路由(记录路由类的实例化),传入默认左右侧页面:

  •   state: {
        leftRouterHistory: new RouterHistory([{ name: 'status' }]), // 左侧路由
        rightRouterHistory: new RouterHistory([{ name: 'logbuch' }]), // 右侧路由
      },

存储路由,形成路由历史:

  •   mutations: {
        [SET_ROUTERHISTORY](state, options) {
          state.leftRouterHistory = options.left;
          state.rightRouterHistory = options.right;
        },
      },
  •  actions: {
        setRouterHistory({ commit }, params) {
          commit(SET_ROUTERHISTORY, params);
        },
      },

三. 使用 vuex 记录路由

1.home.vue 的基本构成

左侧面板:   

  • :is="currentLeftComponent"
                :data="currentLeftParams"

                @toggleComponent="toggleComponent"
                @toggleDialogComponent="toggleDialogComponent">
右侧面板:
  • :is="currentRightComponent"
              :data="currentRightParams"

              @toggleComponent="toggleComponent"
              @toggleDialogComponent="toggleDialogComponent">  

中间弹框:

  • :is="currentDialogComponent" @close-dialog="closeDialogComponent"> 

引入各种 .vue组件:

  • const status = defineAsyncComponent(() => import('./status-analysis/status.vue')); // 实况
    const logbuch = defineAsyncComponent(() => import('./status-analysis/logbuch.vue')); // 战况

定义各个面板默认绑定的组件:

  •     const state = reactive({
          currentLeftComponent: xxx, // 左侧组件名称 —— 此时是写成固定的绑定组件
          currentLeftParams: {}, // 左侧组件参数
          currentRightComponent: xxx, // 右侧组件名称 —— 此时是写成固定的绑定组件
          currentRightParams: {}, // 右侧组件参数
          currentDialogComponent: '', // 中间弹框组件名称
        });

实现切换组件:

  • 子页面触发 home.vue 中的 toggleComponent 方法,实现组件切换
  • 子页面传入的 data 对象中,根据 data 内容,更改各个面板绑定的组件
  • 每次切换组件时,都应自动关闭中间弹框,因此每次都要清空弹框组件
  •     const toggleComponent = (data: any) => {
          state.currentDialogComponent = ''; // 弹框组件清空
          // 左侧
          if (data.left) {
            state.currentLeftComponent = data.left.name;
            state.currentLeftParams = data.left.params;
          }
          // 右侧
          if (data.right) {
            state.currentRightComponent = data.right.name;
            state.currentRightParams = data.right.params;
          }
        };

中间的弹框,本质上是依附于左右面板的子组件,因此想要打开弹框,需要让左右面板监听打开弹窗的事件

  •     const toggleDialogComponent = (data: any) => {
          state.currentDialogComponent = data.name;
        };
  • 关闭中间的弹框,就是弹框本身监听事件了
  •     const closeDialogComponent = () => {
          state.currentDialogComponent = '';
        };

2.在 main.ts 中,引入 vuex 相关内容 store/index.ts

必须引入,不然会导致 home.vue 中无法使用 vuex

  • import store from './store';
    instance.use(store);

3.在 home.vue 中,引入 vuex 相关内容,编写路由切换规则

import { useStore } from 'vuex';

setup() 中,实例化 store:const store = useStore(); // 状态管理

setup() 中,从 store 里读取左右记忆路由对象

  •     const { leftRouterHistory } = store.state;
        const { rightRouterHistory } = store.state;

通过 vuex,更改各个面板默认绑定的组件

  •     const state = reactive({
          currentLeftComponent: leftRouterHistory.getCurrent().name, // 左侧组件名称
          currentLeftParams: {}, // 左侧组件参数
          currentRightComponent: rightRouterHistory.getCurrent().name, // 右侧组件名称
          currentRightParams: {}, // 右侧组件参数
          currentDialogComponent: '', // 中间弹框组件名称
        });

通过 vuex,更改切换组件:

除了静态的切换组件需要更改,还应该给 记录路由 传递更改后的路由

  •     const toggleComponent = (data: any) => {
          state.currentDialogComponent = ''; // 弹框组件清空
          // 左侧
          if (data.left) {
            state.currentLeftComponent = data.left.name;
            state.currentLeftParams = data.left.params;
            leftRouterHistory.push({ name: data.left.name }); // 记录路由
          }
          // 右侧
          if (data.right) {
            state.currentRightComponent = data.right.name;
            state.currentRightParams = data.right.params;
            rightRouterHistory.push({ name: data.right.name }); // 记录路由
          }
          // 更新store里的数据
          store.dispatch('setRouterHistory', {
            left: leftRouterHistory,
            right: rightRouterHistory,
          });

        };

home.vue 卸载之后,应该还原 store 中的记录路由

  •     onUnmounted(() => {
          leftRouterHistory.push({ name: 'status' }); // 记录路由
          rightRouterHistory.push({ name: 'logbuch' }); // 记录路由
          store.dispatch('setRouterHistory', {
            left: leftRouterHistory,
            right: rightRouterHistory,
          });
        });

4.在 vue页面 中,引入 vuex 相关内容,编写路由切换规则

页面元素定义一个返回方法:

  • 引入 vuex:import { useStore } from 'vuex';
  • setup() 中,实例化 vuex:const store = useStore();

实现跳转:

  •     const goBack = () => {
          const { rightRouterHistory } = store.state; // 获取当前面板记录路由
          rightRouterHistory.pop(); // 删除当前页面
          // 跳转
          const data = {
            right: {
              name: rightRouterHistory.getCurrent().name, // 删除当前页面后,此时的 getCurrent() 就相当于获取当前页面的上一级页面了
            },
          };
          emit('toggleComponent', data);
        };
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Lyrelion

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值