SoFunction
Updated on 2025-04-06

Vue implements dynamic routing details

Mainstream implementation methods:

Let’s talk about the advantages of the two methods. After all, if you have never done it before, and you can’t understand it no matter how much you say, you still have to read the code

Front-end control

  • No backend help is needed, the routing table is maintained on the front end
  • The logic is relatively simple and easy to get started

Backend control

  • Relatively safer
  • Routing table maintenance in the database

1. Front-end control

Idea: In the routing configuration,metaAttributes, fields related to extension permissions are determined by judging this permission identifier in the route guard to dynamically increase the route and page jump; for example: we add aroleFields to control roles

Specific plan:

1. Return to the role of the front-end user according to the account of the logged in user.

2. The front-end matches the routing table based on the user's role

3. Make the matched routes to form accessible routes

Core code logic

1. In the file (write static routes and dynamic routes respectively)

import Vue from 'vue'
import Router from 'vue-router'

(Router)

import Layout from '@/layout'

// constantRoutes static routes, mainly login pages, 404 pages, etc. that do not require dynamic routesexport const constantRoutes = [
  {
    path: '/redirect',
    component: Layout,
    hidden: true,
    children: [
      {
        path: '/redirect/:path*',
        component: () => import('@/views/redirect/index')
      }
    ]
  },
  {
    path: '/login',
    component: () => import('@/views/login/index'),
    hidden: true
  },
  {
    path: '/404',
    component: () => import('@/views/error-page/404'),
    hidden: true
  },
  {
    path: '/401',
    component: () => import('@/views/error-page/401'),
    hidden: true
  }
] 

// asyncRoutes dynamic routingexport const asyncRoutes = [
  {
    path: '/permission',
    component: Layout,
    redirect: '/permission/page',
    alwaysShow: true, 
    name: 'Permission',
    meta: {
      title: 'Permission',
      icon: 'lock',
      // The core code can be traversed through the matching roles to see if it is displayed      // This means two characters: admin and editor. This menu can be displayed      roles: ['admin', 'editor']
    },
    children: [
      {
        path: 'page',
        component: () => import('@/views/permission/page'),
        name: 'PagePermission',
        meta: {
          title: 'Page Permission',
          // This means that only admin can display          roles: ['admin']
        }
      }
     ]
    }
]

const createRouter = () => new Router({
  scrollBehavior: () => ({ y: 0 }),
  routes: constantRoutes
})

const router = createRouter()

// This is used to reset the route, it is very useful, don't look at these few lines of codeexport function resetRouter() {
  const newRouter = createRouter()
   =  
}

export default router

2. Store/(maintain a state in vuex, and control whether the menu is displayed by matching roles)

import { asyncRoutes, constantRoutes } from '@/router'

// This method is used to match roles andfunction hasPermission(roles, route) {
  if ( && ) {
    return (role => (role))
  } else {
    return true
  }
}


// This method is to traverse the route through recursion and traverse the authorized routes.export function filterAsyncRoutes(routes, roles) {
  const res = []

  (route => {
    const tmp = { ...route }
    if (hasPermission(roles, tmp)) {
      if () {
         = filterAsyncRoutes(, roles)
      }
      (tmp)
    }
  })

  return res
}

const state = {
  routes: [],
  addRoutes: []
}

const mutations = {
  SET_ROUTES: (state, routes) => {
    // This place maintains two states: addRouters and routes     = routes
     = (routes)
  }
}

const actions = {
  generateRoutes({ commit }, roles) {
    return new Promise(resolve => {
      let accessedRoutes
      if (('admin')) {
        accessedRoutes = asyncRoutes || []
      } else {
        // Core code, pass the route and the obtained role (obtained by the background) to match        accessedRoutes = filterAsyncRoutes(asyncRoutes, roles)
      }
      // Set the matched permissions to set into vuex      commit('SET_ROUTES', accessedRoutes)
      resolve(accessedRoutes)
    })
  }
}

export default {
  namespaced: true,
  state,
  mutations,
  actions
}

3、src/

(Create a new route guard function, you can either extract a file in or extract it)

The code here mainly controls the route jump before checking what routes are accessible. The logic for jumping after login can be written in this place

// 
((to, from, next) => {
  if () { // Determine whether there is a token    if ( === '/login') {
      next({ path: '/' });
    } else {
        // Determine whether the current user has pulled the user_info information      if ( === 0) {
        ('GetInfo').then(res => { // Pull info          const roles = ;
          // Pass the obtained role in order to match it, and generate accessed routes          ('GenerateRoutes', { roles }).then(() => { 
            // Dynamically add accessible routing tables (core code, nothing can be done without it)            ()
            
            // hack method ensures addRoutes is completed            next({ ...to, replace: true })
          })
        }).catch(err => {
          (err);
        });
      } else {
        next() //When you have user permissions, it means that all accessable routes have been generated. If you access the full range of page 404 without permissions will be automatically entered.      }
    }
  } else {
    if (() !== -1) { // On the login-free whitelist, enter directly      next();
    } else {
      next('/login'); // Otherwise, all will be redirected to the login page    }
  }
})

4. The sidebar can take data from vuex for rendering

The core code is fromrouterTake the available route objects to render the sidebar. Whether it is dynamic loading of the front-end or dynamic loading of the back-end, the code is the same.

<!-- layout/components/ -->
<el-menu
:default-active="activeMenu"
:collapse="isCollapse"
:background-color=""
:text-color=""
:unique-opened="false"
:active-text-color=""
:collapse-transition="false"
mode="vertical"
>
    // Loop the retrieved route to the subcomponent as a parameter    <sidebar-item v-for="route in routes" :key="" :item="route" :base-path="" />
</el-menu>
// Get permissioned routesroutes() {
  return this.$
}


<!-- layout/components/ -->
  <template slot="title">
    <item v-if="" :icon=" && " :title="" />
  </template>
  <sidebar-item
    v-for="child in "
    :key=""
    :is-nest="true"
    :item="child"
    :base-path="resolvePath()"
    class="nest-menu"
  />

  props: {
    // route object
    item: {
      type: Object,
      required: true
    },
    isNest: {
      type: Boolean,
      default: false
    },
    basePath: {
      type: String,
      default: ''
    }
  }

The front-end controls routing, and the logic is relatively simple. The back-end only needs to store the user's role, and the front-end matches the user's role. But if new characters are added, it will be very painful and each one needs to be added.

2. Backend control routing

The general idea of ​​back-end control is:The routing configuration is placed in the database table. After the user logs in successfully, the authorized menu is passed to the front-end according to the role permissions, and the front-end is formatted into a structure for page routing recognition, and then rendered to the page menu;

  • After the user logs in, the backend directly generates accessible routing data based on the user's role. Note that this place is data.
  • The front-end converts the route data returned by the back-end into the route structure it needs.

Specific logic:

  • Only some static routes are placed inside.login, 404 and so on
  • Organize a data structure and save it in a table
  • Get routing data from the backend, write a data conversion method, and talk about converting the data into accessible routes
  • Maintain onevuexStatus, save the converted route tovuexin
  • The sidebar also uses data from the route for rendering

Because the front control and back-end control are mostly the same, this is the only way to look at the previous different processes:

1. Store/, send a request to obtain data in vuex

GenerateRoutes({ commit }, data) {
  return new Promise((resolve, reject) => {
    getRoute(data).then(res => {
     // Convert the retrieved data and save it to vuex      const accessedRouters = arrayToMenu()
      ([{ path: '*', redirect: '/404', hidden: true }])
      commit('SET_ROUTERS', accessedRouters)
      resolve()
    }).catch(error => {
      reject(error)
    })
  })
}

2. Organize a data structure and store it in the table

// Page routing format{
    path: '/form',
    component: Layout,
    children: [
      {
        path: 'index',
        name: 'Form',
        component: () => import('@/views/form/index'),
        meta: { title: 'Form', icon: 'form' }
      }
    ]
}

// Organized data format// Level 1 menu// If parentId is 0, it can be used as a first-level menu. It is best to choose 4 digits of id. As for why you will know when you develop a project.{
    id: 1300
    parentId: 0
    title: "Men Management"
    path: "/menu"
    hidden: false
    component: null
    hidden: false
    name: "menu"
},

// Level 2 menu// If the parentId is not 0, you can use parentId to match the id of the first-level menu. If the matching is pushed into children{
    id: 1307
    parentId: 1300
    title: "Submenu"
    hidden: false
    path: "menuItem"
    component: "menu/menuItem" // To match the local file address    hidden: false
    name: "menuItem"
}

3. Write a conversion method to convert the obtained data into a router structure

export function arrayToMenu(array) {
  const nodes = []
  // Get top-level node  for (let i = 0; i < ; i++) {
    const row = array[i]
    // This exists method is to determine whether there are children    if (!exists(array, )) {
      ({
        path: , // Routing address        hidden: , // Just true, if the backend is not matched        component: Layout, // Generally, it is the component that matches your file        name: , //Route name        meta: { title: , icon:  }, // title is the name displayed        id: , // The routed id        redirect: 'noredirect'
      })
    }
  }
  const toDo = (nodes)
  while () {
    const node = ()
    // Get child nodes    for (let i = 0; i < ; i++) {
      const row = array[i]
      // The parentId equals the parentId to which parent is pushed      if ( === ) {
        const child = {
          path: ,
          name: ,
          hidden: ,
          // Core code, because the component of the secondary route needs to match the page          component: require('@/views/' +  + '/'),
          meta: { title: , icon:  },
          id: 
        }
        if () {
          (child)
        } else {
           = [child]
        }
        (child)
      }
    }
  }
  return nodes
}
// Check if there are any childrenfunction exists(rows, parentId) {
  for (let i = 0; i < ; i++) {
    if (rows[i].id === parentId) return true
  }
  return false
}

This is the end of this article about the detailed article on the implementation of dynamic routing of vue. For more related content on the implementation of dynamic routing of vue, please search for my previous articles or continue browsing the related articles below. I hope everyone will support me in the future!