iis服务器助手广告广告
返回顶部
首页 > 资讯 > 前端开发 > JavaScript >详解Vue3如何加载动态菜单
  • 619
分享到

详解Vue3如何加载动态菜单

2024-04-02 19:04:59 619人浏览 独家记忆
摘要

目录1. 整体思路2. 实现细节2.1 加载细节2.2 getInfo2.3 generateRoutes1. 整体思路 首先我们来梳理下整体上的实现思路,首先一点:整体思路和 vh

1. 整体思路

首先我们来梳理下整体上的实现思路,首先一点:整体思路和 vhr 一模一样。

考虑到有的小伙伴可能已经忘记 vhr 中前端动态菜单的实现思路了,因此本文再和大家分析一下。

为了确保在所有的 .Vue 文件中都能访问到到菜单数据,所以选择将菜单数据存入 vuex 中,vuex 是 vue 中一个存储数据的公共地方,所有的 .vue 文件都可以从 vuex 中读取到数据。存储在 vuex 中的数据本质上是存在内存中,所以它有一个特点,就是浏览器按 F5 刷新之后,数据就没了。所以在发生页面的跳转的时候,我们应该去区分一下,是用户点击了页面上的菜单按钮之后发生了页面跳转还是用户点击了浏览器刷新按钮(或者按了 F5)发生了跳转。

为了实现这一点,我们需要用到 vue 中的路由导航守卫功能,对于我们 Java 工程师而言,这些可能听起来有点陌生,但是你把它当作 Java 中的 Filter 来看待就好理解了,实际上我们视频中和小伙伴们讲解的时候就是这么类比的,将一个新事物跟我们脑海中一个已有的熟悉的事物进行类比,就很容易理解了。

vue 中的导航守卫就类似一个监控,它可以监控到所有的页面跳转,在页面跳转中,我们可以去判断一下 vuex 中的菜单数据是否还在,如果还在,就说明用户是点击了页面上的菜单按钮完成了跳转的,如果不在,就说明用户是点击了浏览器的刷新按钮或者是按了 F5 进行页面刷新的,此时我们就要赶紧去服务端重新加载一下菜单数据。

---xxxxxxxxxxxxxxxxxx---

整体上的实现思路就是这样,接下来我们来看看一些具体的实现细节。

2. 实现细节

2.1 加载细节

首先我们来看看加载的细节。

小伙伴们知道,单页面项目的入口是 main.js,路由加载的内容在 src/permission.js 文件中,该文件在 main.js 中被引入,src/permission.js 中的前置导航守卫内容如下:

router.beforeEach((to, from, next) => {
  NProgress.start()
  if (getToken()) {
    to.meta.title && useSettingsStore().setTitle(to.meta.title)
    
    if (to.path === '/login') {
      next({ path: '/' })
      NProgress.done()
    } else {
      if (useUserStore().roles.length === 0) {
        isRelogin.show = true
        // 判断当前用户是否已拉取完user_info信息
        useUserStore().getInfo().then(() => {
          isRelogin.show = false
          usePermissionStore().generateRoutes().then(accessRoutes => {
            // 根据roles权限生成可访问的路由表
            accessRoutes.forEach(route => {
              if (!isHttp(route.path)) {
                router.addRoute(route) // 动态添加可访问路由表
              }
            })
            next({ ...to, replace: true }) // hack方法 确保addRoutes已完成
          })
        }).catch(err => {
          useUserStore().loGout().then(() => {
            ElMessage.error(err)
            next({ path: '/' })
          })
        })
      } else {
        next()
      }
    }
  } else {
    // 没有token
    if (whiteList.indexOf(to.path) !== -1) {
      // 在免登录白名单,直接进入
      next()
    } else {
      next(`/login?redirect=${to.fullPath}`) // 否则全部重定向到登录页
      NProgress.done()
    }
  }
})

我跟大家捋一下这个前置导航守卫中的思路:

  • 首先调用 getToken 方法,这个方法实际上是去 Cookie 中拿认证 Token,也就是登录成功后后端返回给前端的那个 Jwt 字符串
  • 如果 getToken 方法有返回值,说明用户已经登录了,那么进入到 if 分支中,如果 getToken 没拿到值,说明用户未登录,未登录的话,又分为两种情况:i:访问的目标地址处于免登录白名单中,那么此时直接访问即可;ii:访问的目标地址不在白名单中,那么此时就跳转到登录页面去,跳转的时候同时携带一个 redirect 参数,这样方便在登录成功之后,再跳转回访问的目标页面。这个免登录访问的白名单,是一个在 src/permission.js 文件中定义的变量,默认有四个路径,分别是 ['/login', '/auth-redirect', '/bind', '/reGISter']
  • 如果 getToken 拿到了值,说明用户已经登录了,此时又分情况:如果用户访问的路径是登录页面,那么就给他重定向到项目首页(也就是在已经登录的情况下,不允许用户再次访问登录页面);如果用户访问的路径不是登录页面,那么首先判断 vuex 中的 roles 是否还有值?如果有值,说明当前就是用户点击了一个菜单按钮进行跳转的,那么直接跳转就行了;如果没有值,说明用户是按了浏览器的刷新按钮或者是 F5 按钮刷新进行的页面跳转,那么此时首先调用 getInfo 方法(位于 src/store/modules/user.js 文件中)去服务端重新加载当前用户的基本信息、角色信息以及权限信息,然后再调用 generateRoutes 方法(位于 src/store/modules/permission.js 文件中)去服务端加载路由信息,并将加载到的路由信息放入到 router 对象中(前提是这个路由对象不是一个 http 链接,就是普通的路由地址)。

这就是动态路由的加载整体思路。

在第三步骤中,涉及到两个方法,一个是 getInfo 还有一个 generateRoutes,这两个方法也都比较关键,我们再来稍微看下。

2.2 getInfo

首先这个加载用户信息的方法位于 src/store/modules/user.js 文件中,换言之,这些用户的基本信息加载到之后,是存储在 vuex 中的,如果刷新浏览器这些数据就会丢失:

getInfo() {
  return new Promise((resolve, reject) => {
    getInfo().then(res => {
      const user = res.user
      const avatar = (user.avatar == "" || user.avatar == null) ? defAva : import.meta.env.VITE_APP_BASE_api + user.avatar;
      if (res.roles && res.roles.length > 0) { // 验证返回的roles是否是一个非空数组
        this.roles = res.roles
        this.permissions = res.permissions
      } else {
        this.roles = ['ROLE_DEFAULT']
      }
      this.name = user.userName
      this.avatar = avatar;
      resolve(res)
    }).catch(error => {
      reject(error)
    })
  })
},

方法的逻辑其实倒没啥好说的,结合服务端返回的 JSON 格式,应该就很好理解了(部分 JSON):

{
    "permissions":[
        "*:*:*"
    ],
    "roles":[
        "admin"
    ],
    "user":
        "userName":"admin",
        "nickName":"TienChin健身",
        "avatar":"",
    }
}

另外再强调下,之前在 vhr 中,我们是将请求封装成了一个 api.js 文件,里边有常用的 get、post、put 以及 delete 请求等,然后在需要使用的地方,直接去调用这些方法发送请求即可,但是在 TienChin 中,脚手架的封装是将所有的请求都提前统一封装好,在需要的时候直接调用封装好的方法,连请求地址都不用传递了(封装的时候就已经写死了),所以小伙伴们看上面的 getInfo 方法只有方法调用,没有传递路径参数等。

2.3 generateRoutes

generateRoutes 方法则位于 src/store/modules/permission.js 文件中,这里值得说道的地方就比较多了:

generateRoutes(roles) {
  return new Promise(resolve => {
    // 向后端请求路由数据
    getRouters().then(res => {
      const sdata = JSON.parse(JSON.stringify(res.data))
      const rdata = JSON.parse(JSON.stringify(res.data))
      const defaultData = JSON.parse(JSON.stringify(res.data))
      const sidebarRoutes = filterAsyncRouter(sdata)
      const rewriteRoutes = filterAsyncRouter(rdata, false, true)
      const defaultRoutes = filterAsyncRouter(defaultData)
      const asyncRoutes = filterDynamicRoutes(dynamicRoutes)
      asyncRoutes.forEach(route => { router.addRoute(route) })
      this.setRoutes(rewriteRoutes)
      this.setSidebarRouters(constantRoutes.concat(sidebarRoutes))
      this.setDefaultRoutes(sidebarRoutes)
      this.setTopbarRoutes(defaultRoutes)
      resolve(rewriteRoutes)
    })
  })
}

首先大家看到,服务端返回的动态菜单数据解析了三次,分别拿到了三个对象,这三个对象都是将来要用的,只不过使用的场景不同,下面结合页面的显示跟大家细说。

  • 首先是调用 filterAsyncRouter 方法,这个方法的核心作用就是将服务端返回的 component 组件动态加载为一个 component 对象。不过这个方法在调用的过程中,后面还有两个参数,第二个是 lastRouter 在该方法中并无实质性作用;第三个参数则主要是说是否需要对 children 的 path 进行重写。小伙伴们知道,服务端返回的动态菜单的 path 属性都是只有一层的,例如一级菜单系统管理的 path 是 system,二级菜单用户管理的 path 则是 user,那么用户管理最终访问的 path 就是 system/path,如果第三个参数为 true,则会进行 path 的重写,将 path 最终设置正确。
  • 所以这里的 sidebarRoutes 和 defaultRoutes 只是能用于菜单渲染(因为这两个里边的菜单 path 不对),而最终的页面跳转要通过 rewriteRoutes 才可以实现。
  • 除了服务端返回的动态菜单,前端本身也定义了一些基础菜单,前端的基础菜单分为两大类,分别是 constantRoutes 和 dynamicRoutes,其中 constantRoutes 是固定菜单,也就是一些跟用户权限无关的菜单,例如 404 页面、首页等;dynamicRoutes 是动态菜单,也就是也根据用户权限来决定是否展示的菜单,例如分配用户、字典数据、调度日志等等。
  • filterDynamicRoutes 方法则是将前端提前定义好的 dynamicRoutes 菜单进行过滤,找出那些符合当前用户权限的菜单将之添加到路由中(这些菜单都不需要在菜单栏渲染出来)。
  • 接下来涉及到四个不同的保存路由数据的变量,分别是 routes、addRoutes(经松哥分析,这个变量并无实际作用,可以删除之)、defaultRoutes、topbarRouters 以及 sidebarRouters,四个路由变量的作用各有不同:

routes:

routes 中保存的是 constantRoutes 以及服务端返回的动态路由数据,并且这个动态路由数据中的 path 已经完成了重写,所以这个 routes 主要用在两个地方:

首页的搜索上:首页的搜索也可以按照路径去搜索,所以需要用到这个 routes,如下图:

用在 TagsView,这个地方也需要根据页面渲染不同的菜单,也是用的 routes:

sidebarRouters:

这个就是大家所熟知的侧边栏菜单了,具体展示是 constantRoutes+服务端返回的菜单,不过这些 constantRoutes 基本上 hidden 属性都是 false,渲染的时候是不会被渲染出来的。

topbarRouters:

这个是用在 TopNav 组件中,这个是将系统的一级菜单在头部显示出来的,如下图:

一级菜单在顶部显示,左边显示的都是二级三级菜单,那么顶部菜单的渲染,用的就是这个 topbarRouters。

defaultRoutes:

想要开启顶部菜单,需要在 src/layout/components/Settings/index.vue 组件中设置,如下图:

开启顶部菜单之后,点击顶部菜单,左边菜单栏会跟着切换,此时就是从 defaultRoutes 中遍历出相关的菜单设置给 sidebarRouters。

好了,这就是这四个 routes 变量的作用,老实说,脚手架中这块的代码设计有点混乱,没必要搞这么多变量,等松哥抽空给大家优化下。

generateRoutes 方法最终会返回 rewriteRoutes 变量到前面说的那个前置导航守卫中,最终前置导航守卫将数据添加到 router 中。

菜单的渲染都是在 src/layout/components/Sidebar/index.vue 中完成的,看了下都是常规操作,没啥好说的。

到此这篇关于详解vue3如何加载动态菜单的文章就介绍到这了,更多相关Vue3加载动态菜单内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

--结束END--

本文标题: 详解Vue3如何加载动态菜单

本文链接: https://www.lsjlt.com/news/164737.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • 详解Vue3如何加载动态菜单
    目录1. 整体思路2. 实现细节2.1 加载细节2.2 getInfo2.3 generateRoutes1. 整体思路 首先我们来梳理下整体上的实现思路,首先一点:整体思路和 vh...
    99+
    2024-04-02
  • vue3动态加载组件以及动态引入组件详解
    目录1.问题2.分析3.最后总结1.问题 在做一个用vite构建的vue3项目时,动态拉取导入.vue页面,然后控制台一直有以下提示,页面也无法渲染出来。 2.分析 根据上面的报错...
    99+
    2023-03-23
    vue 动态加载组件 vue加载组件 vue3动态加载组件
  • vue如何动态加载组件详解
    目录使用场景:需要动态导入组件的页面核心组件的代码:使用场景:总结使用场景: 项目中需要我们根据不同的业务需求呈现不同的业务场景,如果业务类型简单还好,直接全部引入判断即可,但随着我...
    99+
    2022-11-13
    vue 组件动态加载 vuejs动态加载组件 vue 加载组件
  • vue动态菜单、动态路由加载以及刷新踩坑实战
    目录需求:思路:教训:分享正文:总结需求: 从接口动态获取子菜单数据 动态加载 要求只有展开才加载子菜单数据 支持刷新,页面显示正常 思路: 一开始比较乱,思路很多。想了很多 首先...
    99+
    2024-04-02
  • vue3.x使用swiperUI动态加载图片失败如何解决
    这篇文章主要讲解了“vue3.x使用swiperUI动态加载图片失败如何解决”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“vue3.x使用swiperUI动态加载图片失败如何解决”吧!版本号...
    99+
    2023-07-02
  • 如何利用Vue3管理系统实现动态路由和动态侧边菜单栏
    目录前言动态路由动态侧边菜单栏总结前言 在做Vue管理系统的时候,都会遇到的一个需求:每个用户的权限是不一样的,那么他可以访问的页面(路由),可以操作的菜单选项是不一样的,如果由后端...
    99+
    2024-04-02
  • vue动态菜单如何变中文
    这篇“vue动态菜单如何变中文”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“vue动态菜单如何变中文”文章吧。Vue动态菜单...
    99+
    2023-07-06
  • win11开始菜单加载不出来如何解决
    如果Windows 11开始菜单无法加载,请尝试以下解决方法:1. 重启电脑:有时候重新启动可以解决临时的软件故障或错误。2. 检查...
    99+
    2023-08-21
    win11
  • css如何实现动态二级菜单
    这篇文章将为大家详细讲解有关css如何实现动态二级菜单,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。动态实现简单的二级菜单当鼠标放到一级标签上时,鼠标会变成小手的形状 展示二级菜单,源码如下,复制即可直接...
    99+
    2023-06-08
  • RecyclerChart动态属性图标联动数据动态加载详解
    目录正文图表联动数据动态加载回溯正文 本章节继上一章节中相关的动态属性作介绍,主要讲述三个功能实现点,第一个是上下图表联动问题,类似于股票软件K线上面的Candle图跟下边的MAC...
    99+
    2023-03-02
    RecyclerChart动态属性 RecyclerChart图标联动 RecyclerChart数据动态加载
  • Android如何给Textview添加菜单项详解(Java)
    目录背景描述:解决办法具体步骤:1.创建菜单文件2.给activity添加菜单,重写菜单监听事件3. 给控件添加菜单响应属性 总结背景描述: 界面上有一个Textview和...
    99+
    2024-04-02
  • 如何动态加载JavaScript文件
    这篇文章主要介绍如何动态加载JavaScript文件,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!一、使用document.write/writeln()方式该种方式可以实现js文件...
    99+
    2024-04-02
  • 如何动态加载PHP扩展
    这篇文章给大家介绍如何动态加载PHP扩展,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。查看是否已经加载了扩展echo extension_loaded("redis");非常简单的一个函数...
    99+
    2023-06-20
  • OrchardCore 如何动态加载模块
    这篇文章主要讲解了“OrchardCore 如何动态加载模块”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“OrchardCore 如何动态加载模块”吧!Or...
    99+
    2024-04-02
  • iscroll如何动态加载数据
    这篇文章将为大家详细讲解有关iscroll如何动态加载数据,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。具体内容如下<div id="wrapp...
    99+
    2024-04-02
  • 详解Java类动态加载和热替换
    目录前言1. Java的类加载器和双亲委派模型1.1 Java类加载器1.2 双亲委派模型2. Java的类动态加载和卸载2.1 Java类的卸载2.2 自定义类加载器2.3 动态卸...
    99+
    2024-04-02
  • Android 动态加载 so实现示例详解
    目录背景so动态加载介绍从一个例子出发so库检索与删除动态加载so结束了吗?ELF文件扩展总结背景 对于一个普通的android应用来说,so库的占比通常都是巨高不下的,因为我们无可...
    99+
    2024-04-02
  • vue3动态组件使用详解
    目录vue2vue3markRow:标记一个对象,使其不能成为一个响应式对象。toRaw:将响应式对象(由 reactive定义的响应式)转换为普通对象。shallowRef:只处理...
    99+
    2023-02-27
    vue3中动态组件 vue3动态加载组件 vue3动态添加组件
  • vue3动态加载对话框的方法实例
    目录简介常规方式使用对话框异步动态加载使用方式TestModal.vue使用结果动态操作对话框的实现DzModalService.tsmain.ts总结简介 介绍使用vue3的异步组...
    99+
    2024-04-02
  • vue3动态加载组件及动态引入组件怎么使用
    本篇内容介绍了“vue3动态加载组件及动态引入组件怎么使用”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!1.问题在做一个用vite构建的vu...
    99+
    2023-07-05
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作