Background: The company planned to build a (CMS). At the beginning, the front-end referred to the vue-Element-Admin idea to verify the possibility of front-end authentication, and the code written by the big guy was clear and worth learning. Later, considering many factors, such as interface security, the difficulty of front-end authentication and the complexity of the project, the company finally chose the form of back-end rendering dynamic routing

This paper is relatively out of date, please see Vue in another way of thinking – the realization and optimization of dynamic routing

Using Vue+Element’s backend management template github

The train of thought referred to the article

Vue dynamic routing implementation (back-end routing, front end to get and generate the sidebar)

issues/293

Implementation approach

Some basic ideas and the realization of Vue dynamic routing Vue dynamic routing implementation (back-end routing, front-end get and generate the sidebar), the core part to add their own understanding

  1. Before performing routing logic, check whether you have logged in
  2. Get variablesgetRouterIf yes, the route is allowed because the route configuration exists
  3. If I refresh the pagegetRouterThe variable doesn’t exist, so you have to get it again
  4. Get it in the store togetRouterOn, easy to use later, reduce requests

The following is the specific implementation idea

Configuring basic Routes

The basic route is a route that can be accessed without login

const StaricRouterMap = [
  {
    path: '/login'.component: login,
    hidden: true
  },
  {
    path: '/'.component: Layout,
    redirect: '/dashboard'.name: 'dashboard'.hidden: true.meta: { title: 'Root directory' },
    children: [{path: 'dashboard'.component: (a)= > import('@/views/dashboard/index')}]}, {path: '/ 404'.component: (a)= > import('@/views/404'),
    hidden: true
  },
  {
    path: The '*'.redirect: '/ 404'.hidden: true
  }, / /...
]
export default new Router({
  mode: 'history'.// The back-end support can be turned on
  scrollBehavior: (a)= > ({ y: 0 }),
  routes: StaricRouterMap
})
Copy the code

Customize routing structure with backend students (json below)

The back end will dynamically return the routing structure based on the current user permissions and the front end no longer needs to consider permissions

[{
  "id": 1."name": "Nested"."code": null."description": null."url": "/nested"."generatemenu": 0."sort": 0."parentId": null."permName": null."redirect": "/nested/menu1"."title": "Nested"."icon": "nested"."children": [{
    "id": 2."name": "Menu1"."code": null."description": null."url": "menu1"."generatemenu": 0."sort": 0."parentId": 1."permName": null."redirect": ""."title": "Menu1"."icon": "menu1"."children": [{
      "id": 4."name": "Menu1-1"."code": null."description": null."url": "menu1-1"."generatemenu": 0."sort": 0."parentId": 2."permName": null."redirect": ""."title": "Menu1-1"."icon": ""."children": null
    }, {
      "id": 5."name": "Menu1-2"."code": null."description": null."url": "menu1-2"."generatemenu": 0."sort": 0."parentId": 2."permName": null."redirect": ""."title": "Menu1-2"."icon": ""."children": null}]}, {"id": 3."name": "Menu2"."code": null."description": null."url": "menu2"."generatemenu": 0."sort": 0."parentId": 1."permName": null."redirect": ""."title": "Menu2"."icon": "menu2"."children": null}}]]Copy the code

Parse the back-end initial route data into available data

Of course this is not going to be used directly for rendering routing but we need to recursively process it to get the data that we want

../router/_import

export default file => {
  return map[file] || null
}

const map = {
  Nested: (a)= > import('@/views/layout/Layout'),
  Menu1: (a)= > import('@/views/nested/menu1/index'),
  'Menu1-1': (a)= > import('@/views/nested/menu1/menu1-1'),
  'Menu1-2': (a)= > import('@/views/nested/menu1/menu1-2')}Copy the code

Processing back-end raw routing data

../utils/addRouter

import _import from '.. /router/_import'// Get the method of the component

function addRouter(routerlist) {
  routerlist.forEach(e= > {
    // Delete useless attributes
    delete e.code
    delete e.sort
    delete e.generatemenu
    delete e.description
    delete e.permName
    delete e.id
    delete e.parentId

    e.path = e.url
    delete e.url
    e.component = _import(e.name) // Dynamically match components
    if (e.redirect === ' ') {
      delete e.redirect
    }
    if(e.icon ! = =' '&& e.title ! = =' ') { // Configure the menu title and icon
      e.meta = {
        title: e.title,
        icon: e.icon
      }
    }
    if(e.title ! = =' ' && e.icon === ' ') {
      e.meta = {
        title: e.title
      }
    }
    delete e.icon
    delete e.title
    if(e.children ! =null) {
      // Recurse if there are child routes
      addRouter(e.children)
    }
  })
  return routerlist
}

export { addRouter }
Copy the code

Route after processing

The processed route needs to be spliced with the existing router. The rules for processing routes need to be modified as required

[{
  "name": "Nested"."redirect": "/nested/menu1"."children": [{
    "name": "Menu1"."children": [{
      "name": "Menu1-1"."children": null."path": "menu1-1"."meta": {
        "title": "Menu1-1"}}, {"name": "Menu1-2"."children": null."path": "menu1-2"."meta": {
        "title": "Menu1-2"}}]."path": "menu1"."meta": {
      "title": "Menu1"."icon": "menu1"}}, {"name": "Menu2"."children": null."path": "menu2"."component": null."meta": {
      "title": "Menu2"."icon": "menu2"}}]."path": "/nested"."meta": {
    "title": "Nested"."icon": "nested"}}]Copy the code

(Core) Merge routes

This is all preparation to concatenate the initial route with the dynamic route returned from the back end

Here is also the most complex piece, referring to some other people’s ideas, and later completed this version, this is the top implementation of the idea of the code

import router from './router'
import store from './store'
import NProgress from 'nprogress' // The Progress bar
import 'nprogress/nprogress.css' // Progress bar style
import { Message } from 'element-ui'
import { addRouter } from './utils/addRouter'

var getRouter
router.beforeEach((to, from, next) = > {
  NProgress.start() / / the progress bar
  if (localStorage.getItem('login_static') = = ='1') {
    if (to.path === '/login') {
      Message('You have logged in. If you want to switch users, please log out and log in again.')
      next({ path: '/'})}if(! getRouter) {if (getRouterList('router')) {
        // The presence of routing information indicates the request phase and the completion of direct parsing of routing information
        getRouter = getRouterList('router') // Get the route
        gotoRouter(to, next)
      } else {
        // localStorage does not have routing information. This requires requesting routing information and resolving the route
        setRouterList(to, next) // Route the storage to localStorage}}else {
      // If the getRouter variable exists, the route information exists directly
      next()
    }
  } else {
    if (to.path === '/login') {
      next()
    } else {
      next(`/login`)
    }
  }
})

router.afterEach((a)= > {
  NProgress.done() / / end of Progress
})

function gotoRouter(to, next) {
  try {
    getRouter = addRouter(getRouter)
    router.addRoutes(getRouter) // Add a route dynamically
    global.antRouter = router.options.routes.concat(getRouter) // Pass the routing data to the global variable and render the sidebar menu
    next({ to, replace: true})}catch (error) {
    localStorage.setItem('login_static'.0)}}function setRouterList(to, next) {
  store.dispatch('getRouter').then(asyncRouter= > { // Request routing data
    localStorage.setItem('router'.JSON.stringify(asyncRouter))
    getRouter = getRouterList('router') // Get the route
    gotoRouter(to, next)
  })
}

function getRouterList(name) {
  return JSON.parse(localStorage.getItem(name))
}
Copy the code

Change the application routing address in the sidebar

Note that the routes merged by addRoutes are not obtained by this.$router.options.routes, so you need to concatenate the obtained routes to this

Finally modify the code to render part of the sidebar

src\views\layout\components\Sidebar\index.vue

 computed: {
	/ /...
    routes() {
      return global.antRouter // It would be better to use the vuex global variable
    },
   	/ /...
  }
Copy the code