preface

  • Music Blog is online!
  • This dynamic route has been integrated into music Blog. If necessary, you can check permission file, Vuex store file, router route
  • If you are asked in an interview what are the highlights of your project?
  • You are still in embarrassment of the lower the head to say: ordinary add delete change check display page?
  • The following shows how using dynamic routing in a project becomes a small highlight!

This picture is the weekend with my girlfriend to visit K11 feel very good, specially to share with all ape friends appreciate, hope we can play route like a little girl, free flying


Dynamic routing

Why use dynamic routing?

A lot of the routing in our projects is configured on the front end

But sometimes in order to carry out comprehensive permission control, it is necessary to present the routing table in the background and render it in the front. No front-end configuration. For example: according to the user’s role, log in to display different menus

Train of thought to sort out

  • There is role management in the menu. Adding a role to the page corresponds to the menu to be displayed is equivalent to transferring the routing table data configured in the front end to the back-end database

  • We need to process the data ourselves

    • In the routingcomponentThe background can not be given, here we only need the background according to the front-end we providecomponentPath to the data, because the back end returns a component path as a string, and the front end needs a component object, write a method to loop in and convert the string to a component object
    const loadViewsd = (view: any) = > {
      return (resolve: any) = > require(
        [`@/views/${view}.vue`], resolve
    )}
    Copy the code
    • So we have the most important data, namelycomponent
  • Use vuerouter’s beforeEacg, addRoutes to match the previous two steps

  • Processing the data provided in the background into the routing table we need

  • Add Router. AddRoutes (Routing data)

1. The back end returns a routing table in JSON format. 2. The back end returns a string format, but the front end needs a component object. Use the beforeEach, addRoutes, vuex of vuE-Router to coordinate with the previous two steps to achieve effect 4. The left menu interception displays the route according to the translated route list. Interception route -> back end fetch route -> save route to VUEX (the user will only fetch route from back end once when logging in, and the rest will be fetched from local, so the user will update the route only after logging out)

Code implementation

Create a new router.js

Each route uses the component Layout, which is the overall page Layout: menu column on the left and page on the right. Therefore, the first-level route under Children is your own page. The meta contains the name of the route and the corresponding icon of the route.

Because there may be multi-level menus, children will be nested under children;

Routes are in array format

export const asyncRoutes = [
  {
    path: '/permission'.    // // component: Layout,
    componentUrl: 'Layout'. redirect: '/permission/directive'. meta: {  title: 'permission'. icon: 'lock'. alwaysShow: true // will always show the root menu  }  },  {  path: '/sys'. // // component: Layout,  componentUrl: 'Layout'. meta: {  title: 'sys'. icon: 'example'. roles: ['admin'].// you can set roles in root nav  alwaysShow: true.// will always show the root menu  noCache: true  },  children: [  {  path: 'sys-user'. // // component: () => import(/* webpackChunkName: "sys-user" */ '@/views/sys/sys-user.vue'),  componentUrl: 'sys/sys-user'. name: 'sysUser'. meta: { title: 'sysUser'.noCache: true }  },  {  path: 'sys-menu'. // // component: () => import(/* webpackChunkName: "sys-menu" */ '@/views/sys/sys-menu.vue'),  componentUrl: 'sys/sys-menu'. name: 'sysMenu'. meta: { title: 'sysMenu'.noCache: true }  },  {  path: 'sys-role'. // // component: () => import(/* webpackChunkName: "sys-role" */ '@/views/sys/sys-role.vue'),  componentUrl: 'sys/sys-role'. name: 'sysRole'. meta: { title: 'sysRole'.noCache: true }  }  ]  } ] Copy the code

The basic routing table has been established

When do we get the complete routing table data

We need to route the hook function in router. beforeEach

router.beforeEach(async (to: Route, _: Route, next: any) => {
  // Start progress bar
  NProgress.start()

  // Determine whether the user has logged in
 if (UserModule.token) {  if (to.path === '/login') {  next({ path: '/' })  NProgress.done()  } else {  // Enter the first time you log in  if (UserModule.roles.length === 0) {  try {  // Note: roles must be a object array! such as: ['admin'] or ['developer', 'editor']  await UserModule.GetUserInfo() // Get the user role  const roles = UserModule.roles  // Generate accessible routes map based on role  PermissionModule.GenerateRoutes(roles) // Render the route to our menu  // If it is empty, then go to the database to read the render to the menu  if (PermissionModule.dynamicRoutes.length === 0) {  const { data } = await getSysRole({  page: 1. limit: 8. roleKey: roles[0]  })  PermissionModule.dynamicRoutes = filterAsyncRouter(data.items[0].routes)  }   router.addRoutes(PermissionModule.dynamicRoutes) // Dynamically add routes  next({ ... to,replace: true })  } catch (err) {  // Remove token and redirect to login page  UserModule.ResetToken()  Message.error(err || 'Has Error')  next(`/login? redirect=${to.path}`)  NProgress.done()  }  } else {  next()  }  }  } else {} }) Copy the code

Next we look at the above PermissionModule. GenerateRoutes (roles) method

This method is written in our vuex.store

@Action
  public async GenerateRoutes(roles: string[]) {
    let accessedRoutes
    if (roles.includes('admin')) {
AccessedRoutes = adminRoutes // is the router.js we defined above } else { // The non-administrator gets the user's role menu for the back-end read database const {data} = await getSysRole({  page: 1,  limit: 8,  roleKey: roles[0]  })  accessedRoutes = filterAsyncRouter(data.items[0].routes)   }  this.SET_ROUTES(accessedRoutes)  }  // Iterate over the route string from the background and convert it to a component objectexport const filterAsyncRouter = (asyncRouterMap: any) =>{  const accessedRouters = asyncRouterMap.filter((route: any) => {  if (route.componentUrl) {  if (route.componentUrl === 'Layout') {//Layout component special handling route.component = Layout Delete route.componenturl // there is a pit, please delete it manually after assigning the value, because package compilation failed, because route does not have this attribute } else {  route.component = loadViewsd(route.componentUrl)  delete route.componentUrl  }  }  if (route.children && route.children.length) {  route.children = filterAsyncRouter(route.children)  }  return route  })  // In the case of a complete mismatch, 404 is returned, and routes are matched from top to bottom. The last star matches all of them, accessedRouters.push({  path: The '*'. redirect: '/ 404'. meta: { hidden: true }  })   return accessedRouters }  // String path to component object// Return the backend"componentUrl": "Layout", to"component": Layout Component objectexport const loadViewsd = (view: any) => {  return (resolve: any) => require([`@/views/${view}.vue`], resolve) } Copy the code

Pits encountered by dynamic routing

Package compilation failed

-serve:’vue-cli-service serve’ -serve:’vue-cli-service serve’

thinking

At first glance, I thought there was a problem with node-modules, and then I reinstalled it, and it didn’t work

The solution

This error must be caused by the overall configuration file, check whether there is something added to the vue.config.js file, you can comment it out and try, because I have this project built successfully on Github.

So I pulled down and compared it, and found it was the problem of dynamic routing. It can be seen that the following is the definition type of TS. Our route defines RouteConfig, but there is no componentUrl attribute in vue-Router source code, and THEN I manually added it during development. The development can run successfully, but the packaging of the time is failed to compile, because he vue-Router source code is not componentUrl this attribute;

How did I solve this problem later? I copied the router.js file again and defined it as any type and solved it.

import Router, { RouteConfig } from 'vue-router'
export const asyncRoutes: RouteConfig[] = [
  {
    path: '/permission'.    component: Layout,
 componentUrl: 'Layout'. redirect: '/permission/directive'. meta: {  title: 'permission'. icon: 'lock'. alwaysShow: true // will always show the root menu  },  children: [  {  path: 'page'. component: () => import(/* webpackChunkName: "permission-page"* /'@/views/permission/page.vue'),  componentUrl: 'permission/page'. name: 'PagePermission'. meta: {  title: 'pagePermission'  }  }  ]  } ] Copy the code

Dynamic route loading failed. Procedure

The solution

FilterAsyncRouter () {componentUrl (route) {componentUrl (route) {route (Route) {route (Route) {route (route)

The original link

Juejin. Cn/post / 687234…

Reference documentation

Vue dynamic routing implementation (background routing, front end to get and generate sidebar)

Vue implements dynamic routing

This article is formatted using MDNICE