vue3实现动态路由及菜单

 更新时间:2024年03月04日 16:22:52   作者:左直拳  
这篇文章主要介绍了vue3实现动态路由及菜单,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教

一般来说,前端项目中的路由,很有可能是需要动态注册的。

因为菜单可能在管理系统中维护,还跟权限绑定,用户登录以后,需要动态展示菜单。

菜单往往跟路由挂钩,因此,路由需要动态注册。

具体如何实现呢?

思路是,系统只提供默认的路由,登录以后,读入菜单/路由数据,加载。

这其中,可能会出现默认路由与动态路由有重叠的情况。

处理办法是覆盖。数据结构方面,菜单与路由数据二合一。

一、项目结构

这是我们一个项目的公共框架的代码结构。

我们打算在src/modules/存放具体业务系统的代码,而外部是相对稳定,可以复用的框架代码。

二、默认路由

src/router/default.js,内容比较少,只有登录、首页、404三个。其余全都靠动态注册。

路由项中,自定义属性放在meta里。动态路由与默认路由的数据结构一致。

/**
 * 默认路由
 * 具体业务路由,应在src/modules/router里定义,或者从后端动态加载
 */
export default [
  /**
   * 路由项结构:
   *{
      path: "/",//路径,(必选;path、name、component是路由规定必选的元素)
                  也可以带参数,如 path: "/resource/detail/:id",
      name: "路由名称,是路由唯一标识",(必选)
      component: 指向组件,如 Home,或者() => import("../views/login/PageIndex.vue"),(必选)
      meta: {//meta里的属性可以自定义,全部为可选项
        text: "名称",//展示在菜单里,(可选)
        navi: true, //导航条(一级菜单),(可选)
        noLogin: true, //无须登录即可浏览,(可选)
        access: "work:sysmanage,work:resourcemanage",//权限标识,(可选)
      },
      children: [],
    },
   */
  {
    path: "/login",
    name: "login",
    component: () => import("../views/login/PageIndex.vue"),
    meta: {
      noLogin: true, //无须登录即可浏览
    },
  },
  {
    path: "/",
    name: "Home",
    component: () => import("../views/PageIndex.vue"),
  },
  {
    path: "/notAllow",
    name: "notAllow",
    component: () => import("../views/sys/notAllow.vue"),
  },
];

export const HomeName = "Home";

三、动态注册

注册的时机是什么?在哪里注册?怎么注册?

答曰:登录之后注册;在路由守卫里注册;用router.addRoute()一个个加进去。

1、登录之后进行注册,在路由卫士里注册

所谓路由守卫,就是路由规则。这名字我是从网上抄过来的。

src/router/index.js

import { createRouter, createWebHashHistory } from "vue-router";
import routes from "./default";
import routeAssembler from "./setup";
import { hasAuthority } from "@/utils/login.js";

const router = createRouter({
  history: createWebHashHistory(),
  routes,
});

// 路由守卫
let registerRouteFresh = true;//是否还没有动态加载过
router.beforeEach((to, from, next) => {
  const isLogin = localStorage.isLogin ? true : false;
  if (isLogin) {
    //已登录情况下验证权限
    let isAccess = hasAuthority(to.meta.access);
    if (!isAccess) {//没有权限
      next("/notAllow");
      return;
    }
    if (registerRouteFresh) {//还没有动态加载过
      //动态注册路由 <----------------------------------------
      routeAssembler(router);
      registerRouteFresh = false;
      next({ ...to, replace: true });
    } else {
      //已经登录了,不能再打开登录页
      to.path === "/login" ? next("home") : next();
    }
  } else {
    //如果无须登录则直接打开,否则转向登录页面
    to.meta.noLogin || to.path === "/login" ? next() : next("/login");
  }
});

export default router;

2、如何动态注册

src/router/setup.js,即上面例子中的routeAssembler:

/*
  装配路由及菜单
 */
import fixItems from "./default"; //默认路由
import { HomeName } from "./default"; //统一命名首页路由项(参考前面的默认路由)
import projectItems from "@/modules/router"; //具体业务系统的路由

export default (router) => {
  //获得动态路由
  const dynaItems = getDynamicItems();

  //对齐首页(统一命名首页)
  adpatHome(HomeName, dynaItems);

  //添加动态路由
  dynaItems.forEach((value) => {
    router.addRoute(value);
  });
};

const getDynamicItems = () => {
  /*
    获取动态路由,从指定文件加载或从后端获取
  */
  return projectItems;
};

//默认路由与业务路由对齐首页的路由信息
//所谓对齐,就是大家的name保持一致,这样才能保证动态加入的路由项,覆盖掉前面的path和name相同的路由
const adpatHome = (HomeName, dynaItems) => {
  let home = dynaItems.filter((item) => {
    return item.path === "/";
  });
  if (home.length > 0 && home[0].name !== HomeName) {
    /**
     * 如果业务路由定义了首页,但其name与默认路由首页的name不相同
     * 则将业务路由中首页项的name置为默认名称
     * 因为按照vue-router的规则,addRoute的时候,如果存在同名同路径的路由项,则覆盖之
     * 我们要的就是覆盖默认,以业务路由设置为准
     */
    home[0].name = HomeName;
  }
};

这里面有个如果动态路由,与默认路由中存在相同的路由项,该如何处理的问题。

按照vue3的router规则,如果后面加进来的路由项,仅仅是path相同,而name不同,则不算是相同的路由项,addRoute()进去之后,仍然是原先的路由项起作用;但如果是path和name都相同,则原先的会被覆盖(我怀疑是name相同就会被覆盖)。

所以,默认路由中有首页路由,指向框架代码中的默认首页;加载动态路由后,该路由被覆盖,指向了具体业务系统的首页。这也表明,我们无须自己手动删除已加载的同名路由项。

事实上,删除还会报错。

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

相关文章

  • 基于vue 添加axios组件,解决post传参数为null的问题

    基于vue 添加axios组件,解决post传参数为null的问题

    下面小编就为大家分享一篇基于vue 添加axios组件,解决post传参数为null的问题,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2018-03-03
  • vue与django(drf)实现文件上传下载功能全过程

    vue与django(drf)实现文件上传下载功能全过程

    最近简单的学习了django和drf上传文件(主要是图片),做一个记录,下面这篇文章主要给大家介绍了关于vue与django(drf)实现文件上传下载功能的相关资料,需要的朋友可以参考下
    2023-02-02
  • vue预览本地pdf文件方法之vue-pdf组件使用

    vue预览本地pdf文件方法之vue-pdf组件使用

    这篇文章主要介绍了vue预览本地pdf文件方法之vue-pdf组件使用方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2024-03-03
  • Vue中大屏适配和局部适配的方案总结

    Vue中大屏适配和局部适配的方案总结

    这篇文章主要为大家详细介绍了如何通过Vue.js的Mixins功能结合JavaScript实现页面内容的自适应缩放,以适应不同比例的屏幕,需要的小伙伴可以参考下
    2025-03-03
  • 在 Vue 应用中使用 Netlify 表单功能的方法详解

    在 Vue 应用中使用 Netlify 表单功能的方法详解

    Netlify 带有内置表单处理功能,可以用来存储表单数据,下载 csv 文件,同时可以在接收到新的提交时发送邮件通知或者通过配置 webhook 发送请求。这篇文章主要介绍了在 Vue 应用中使用 Netlify 表单功能,需要的朋友可以参考下
    2019-06-06
  • webpack安装配置与常见使用过程详解(结合vue)

    webpack安装配置与常见使用过程详解(结合vue)

    这篇文章主要介绍了webpack安装配置与常见使用过程,主要结合vue实现,通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-06-06
  • Vue3项目中的hooks的使用教程

    Vue3项目中的hooks的使用教程

    今天我们稍微说一下 vue3 项目中的 hooks 的使用,其实这个 hooks 呢是和 vue2 当中的 mixin 是类似的,学习过 vue2 的小伙伴一定对 mixin 一定比较熟悉,快跟随小编一起来学习学习吧
    2022-08-08
  • Vue 实现树形视图数据功能

    Vue 实现树形视图数据功能

    这篇文章主要介绍了Vue 实现树形视图数据功能,利用简单的树形视图实现的,在实现过程中熟悉了组件的递归使用,感兴趣的朋友跟随脚本之家小编一起学习吧
    2018-05-05
  • vue3(vite)设置代理封装axios api解耦功能

    vue3(vite)设置代理封装axios api解耦功能

    这篇文章主要介绍了vue3(vite)设置代理封装axios api解耦,本文结合示例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2022-12-12
  • vue 里面使用axios 和封装的示例代码

    vue 里面使用axios 和封装的示例代码

    本篇文章主要介绍了vue 里面使用axios 和封装的示例代码,非常具有实用价值,需要的朋友可以参考下
    2017-09-09

最新评论