Table of Contents
1. Overall idea
2. Implementation details
2.1 Loading details
2.2 getInfo
2.3 generateRoutes
Home Web Front-end Vue.js How to load dynamic menu in Vue3

How to load dynamic menu in Vue3

May 10, 2023 pm 01:58 PM
vue3

1. Overall idea

First of all, let’s sort out the overall implementation idea. First of all: The overall idea is exactly the same as vhr.

Considering that some friends may have forgotten the implementation idea of ​​the front-end dynamic menu in vhr, this article will analyze it with you.

In order to ensure that the menu data can be accessed in all .vue files, we choose to store the menu data in vuex. vuex is a common place for storing data in vue. All .vue files can read data from vuex. The data stored in vuex is essentially stored in memory, so it has a characteristic that after the browser presses F5 to refresh, the data is gone. So when a page jump occurs, we should distinguish whether the page jump occurs after the user clicks the menu button on the page or whether the page jump occurs after the user clicks the browser refresh button (or presses F5).

In order to achieve this, we need to use the route navigation guard function in vue. For us Java engineers, these may sound a bit unfamiliar, but you can treat it as a Filter in Java. It’s easy to understand. In fact, we used this analogy when explaining it to our friends in the video. It’s easy to understand by comparing a new thing to an already familiar thing in our minds.

The navigation guard in vue is similar to a monitor. It can monitor all page jumps. During page jumps, we can judge whether the menu data in vuex is still there. If it is still there, It means that the user clicked the menu button on the page to complete the jump. If it is not there, it means that the user clicked the browser's refresh button or pressed F5 to refresh the page. At this time, we need to quickly go to the server. Reload the menu data.

---xxxxxxxxxxxxxxxxxxxxx---

The overall implementation idea is like this. Next, let’s take a look at some specific implementation details.

2. Implementation details

2.1 Loading details

First let’s take a look at the loading details.

As you know, the entrance to the single-page project is main.js, and the content loaded by the route is in the src/permission.js file, which is introduced in main.js. The content of the front navigation guard in src/permission.js is as follows:

router.beforeEach((to, from, next) => {
  NProgress.start()
  if (getToken()) {
    to.meta.title && useSettingsStore().setTitle(to.meta.title)
    /* has token*/
    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()
    }
  }
})
Copy after login

Let me walk you through the ideas in this front navigation guard:

  • First call getToken Method, this method actually gets the authentication token from the cookie, which is the JWT string that the backend returns to the frontend after successful login.

  • If the getToken method has a return value, it means that the user has logged in, then enter the if branch. If getToken does not get the value, it means that the user is not logged in. If not, it is divided into There are two situations: i: the accessed target address is in the login-free whitelist, then you can access it directly; ii: the accessed target address is not in the whitelist, then you will jump to the login page at this time, jump At the same time, it carries a redirect parameter, so that after successful login, it is convenient to jump back to the target page visited. This whitelist for login-free access is a variable defined in the src/permission.js file. There are four default paths, namely ['/login', '/auth-redirect', '/bind' , '/register'].

  • If getToken gets the value, it means that the user has logged in. At this time, there are different situations: if the path the user accesses is the login page, then he will be redirected to the project homepage (also That is, if the user is already logged in, the user is not allowed to access the login page again); if the path the user accesses is not the login page, then first determine whether the roles in vuex still have a value? If there is a value, it means that the user clicked a menu button to jump, so just jump directly; if there is no value, it means that the user pressed the browser's refresh button or the F5 button to refresh the page. Then first call the getInfo method (located in the src/store/modules/user.js file) to reload the current user's basic information, role information and permission information on the server, and then call the generateRoutes method (located in src/store/modules /permission.js file) go to the server to load routing information, and put the loaded routing information into the router object (provided that this routing object is not an http link, but an ordinary routing address).

This is the overall idea of ​​loading dynamic routing.

In the third step, two methods are involved, one is getInfo and the other is generateRoutes. These two methods are also critical. Let’s take a closer look.

2.2 getInfo

First of all, this method of loading user information is located in the src/store/modules/user.js file. In other words, after the basic information of these users is loaded , is stored in vuex. If you refresh the browser, these data will be lost: The logic of the

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)
    })
  })
},
Copy after login

method is actually not much to say. Combined with the JSON format returned by the server, it should be easy to understand ( Partial JSON):

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

另外再强调下,之前在 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)
    })
  })
}
Copy after login

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

  • 首先是调用 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,如下图:

How to load dynamic menu in Vue3

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

How to load dynamic menu in Vue3

sidebarRouters:

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

How to load dynamic menu in Vue3

topbarRouters:

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

How to load dynamic menu in Vue3

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

defaultRoutes:

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

How to load dynamic menu in Vue3

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

Okay, this is the role of these four routes variables. To be honest, the code design in this part of the scaffolding is a bit confusing. There is no need to have so many variables. Let Brother Song take the time to optimize it for everyone.

ThegenerateRoutes method will eventually return the rewriteRoutes variable to the front navigation guard mentioned above, and finally the front navigation guard will add the data to the router.

The rendering of the menu is done in src/layout/components/Sidebar/index.vue. After looking at it, it is a normal operation. There is nothing to say.

The above is the detailed content of How to load dynamic menu in Vue3. For more information, please follow other related articles on the PHP Chinese website!

Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn

Hot AI Tools

Undresser.AI Undress

Undresser.AI Undress

AI-powered app for creating realistic nude photos

AI Clothes Remover

AI Clothes Remover

Online AI tool for removing clothes from photos.

Undress AI Tool

Undress AI Tool

Undress images for free

Clothoff.io

Clothoff.io

AI clothes remover

Video Face Swap

Video Face Swap

Swap faces in any video effortlessly with our completely free AI face swap tool!

Hot Article

Roblox: Bubble Gum Simulator Infinity - How To Get And Use Royal Keys
3 weeks ago By 尊渡假赌尊渡假赌尊渡假赌
Nordhold: Fusion System, Explained
4 weeks ago By 尊渡假赌尊渡假赌尊渡假赌
Mandragora: Whispers Of The Witch Tree - How To Unlock The Grappling Hook
3 weeks ago By 尊渡假赌尊渡假赌尊渡假赌

Hot Tools

Notepad++7.3.1

Notepad++7.3.1

Easy-to-use and free code editor

SublimeText3 Chinese version

SublimeText3 Chinese version

Chinese version, very easy to use

Zend Studio 13.0.1

Zend Studio 13.0.1

Powerful PHP integrated development environment

Dreamweaver CS6

Dreamweaver CS6

Visual web development tools

SublimeText3 Mac version

SublimeText3 Mac version

God-level code editing software (SublimeText3)

Hot Topics

Java Tutorial
1669
14
PHP Tutorial
1273
29
C# Tutorial
1256
24
How to refresh partial content of the page in Vue3 How to refresh partial content of the page in Vue3 May 26, 2023 pm 05:31 PM

To achieve partial refresh of the page, we only need to implement the re-rendering of the local component (dom). In Vue, the easiest way to achieve this effect is to use the v-if directive. In Vue2, in addition to using the v-if instruction to re-render the local dom, we can also create a new blank component. When we need to refresh the local page, jump to this blank component page, and then jump back in the beforeRouteEnter guard in the blank component. original page. As shown in the figure below, how to click the refresh button in Vue3.X to reload the DOM within the red box and display the corresponding loading status. Since the guard in the component in the scriptsetup syntax in Vue3.X only has o

How to use tinymce in vue3 project How to use tinymce in vue3 project May 19, 2023 pm 08:40 PM

tinymce is a fully functional rich text editor plug-in, but introducing tinymce into vue is not as smooth as other Vue rich text plug-ins. tinymce itself is not suitable for Vue, and @tinymce/tinymce-vue needs to be introduced, and It is a foreign rich text plug-in and has not passed the Chinese version. You need to download the translation package from its official website (you may need to bypass the firewall). 1. Install related dependencies npminstalltinymce-Snpminstall@tinymce/tinymce-vue-S2. Download the Chinese package 3. Introduce the skin and Chinese package. Create a new tinymce folder in the project public folder and download the

vue3+vite: How to solve the error when using require to dynamically import images in src vue3+vite: How to solve the error when using require to dynamically import images in src May 21, 2023 pm 03:16 PM

vue3+vite:src uses require to dynamically import images and error reports and solutions. vue3+vite dynamically imports multiple images. If vue3 is using typescript development, require will introduce image errors. requireisnotdefined cannot be used like vue2 such as imgUrl:require(' .../assets/test.png') is imported because typescript does not support require, so import is used. Here is how to solve it: use awaitimport

How Vue3 parses markdown and implements code highlighting How Vue3 parses markdown and implements code highlighting May 20, 2023 pm 04:16 PM

Vue implements the blog front-end and needs to implement markdown parsing. If there is code, it needs to implement code highlighting. There are many markdown parsing libraries for Vue, such as markdown-it, vue-markdown-loader, marked, vue-markdown, etc. These libraries are all very similar. Marked is used here, and highlight.js is used as the code highlighting library. The specific implementation steps are as follows: 1. Install dependent libraries. Open the command window under the vue project and enter the following command npminstallmarked-save//marked to convert markdown into htmlnpmins

How to use Vue3 reusable components How to use Vue3 reusable components May 20, 2023 pm 07:25 PM

Preface Whether it is vue or react, when we encounter multiple repeated codes, we will think about how to reuse these codes instead of filling a file with a bunch of redundant codes. In fact, both vue and react can achieve reuse by extracting components, but if you encounter some small code fragments and you don’t want to extract another file, in comparison, react can be used in the same Declare the corresponding widget in the file, or implement it through renderfunction, such as: constDemo:FC=({msg})=>{returndemomsgis{msg}}constApp:FC=()=>{return(

How to select an avatar and crop it in Vue3 How to select an avatar and crop it in Vue3 May 29, 2023 am 10:22 AM

The final effect is to install the VueCropper component yarnaddvue-cropper@next. The above installation value is for Vue3. If it is Vue2 or you want to use other methods to reference, please visit its official npm address: official tutorial. It is also very simple to reference and use it in a component. You only need to introduce the corresponding component and its style file. I do not reference it globally here, but only introduce import{userInfoByRequest}from'../js/api' in my component file. import{VueCropper}from'vue-cropper&

How to use vue3+ts+axios+pinia to achieve senseless refresh How to use vue3+ts+axios+pinia to achieve senseless refresh May 25, 2023 pm 03:37 PM

vue3+ts+axios+pinia realizes senseless refresh 1. First download aiXos and pinianpmipinia in the project--savenpminstallaxios--save2. Encapsulate axios request-----Download js-cookienpmiJS-cookie-s//Introduce aixosimporttype{AxiosRequestConfig ,AxiosResponse}from"axios";importaxiosfrom'axios';import{ElMess

How to solve the problem that after the vue3 project is packaged and published to the server, the access page displays blank How to solve the problem that after the vue3 project is packaged and published to the server, the access page displays blank May 17, 2023 am 08:19 AM

After the vue3 project is packaged and published to the server, the access page displays blank 1. The publicPath in the vue.config.js file is processed as follows: const{defineConfig}=require('@vue/cli-service') module.exports=defineConfig({publicPath :process.env.NODE_ENV==='production'?'./':'/&

See all articles