Regarding the routing of the background management system, I want to take a moment to thoroughly organize a bit of routing to achieve dynamic routing.
First of all, this article is a usage note based on Flower Pants god's "Hand Touch, Take You Background with vue ken", which builds on his project to help a buddy who wants to achieve dynamic routing.
Why is dynamic routing implemented?
In the process of developing the background management system, there will be different people to operate the system, admin (administrator), superAdmin (super tube), as well as various operators and financial personnel.To differentiate these people, we assign different roles to different people to show different menus, which must be done through dynamic routing.
Mainstream implementation:
Simply talk about the advantages of the two ways, after all, if you've never done it before, and you can't understand it any more, you still have to see the code.
front control
1. Routing table maintenance on the front end without backend help 2. The logic is relatively simple and easy to use. Copy Code
2. Backend control
1. A little safer 2. Routing table maintenance in database Copy Code
1. Front End Control
The Trousers god's scheme is front-end control, whose core is to control the loading of routes through role s through the meta-attributes of routes.Specific implementation:
1. Return the role of the front-end user based on the account of the logged-in user 2. Front end matches meta.role of routing table according to user's role 3. Talk about matching routes to form accessible routes Copy Code
Specific code logic:
1. Write both static and dynamic routes in router.js 2. Maintain a state in vuex to control menu display by assigning roles 3. Create a new routing guard function, either in main.js or pull out a file 4. Sidebar can take data from vuex for rendering Copy Code
The core code consists of four files, basically with source code and explanations:
1. In router.js file (write static and dynamic routes in router.js, respectively)
import Vue from 'vue' import Router from 'vue-router' Vue.use(Router) import Layout from '@/layout' // constantRoutes static routing, mainly login pages, 404 pages, etc. do not require dynamic routing export 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 Routing export const asyncRoutes = [ { path: '/permission', component: Layout, redirect: '/permission/page', alwaysShow: true, name: 'Permission', meta: { title: 'Permission', icon: 'lock', // Core code that can be traversed through matching roles to show whether or not // This means 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 show roles: ['admin'] } } ] } ] const createRouter = () => new Router({ scrollBehavior: () => ({ y: 0 }), routes: constantRoutes }) const router = createRouter() // This is useful for resetting routes, not to mention lines of code export function resetRouter() { const newRouter = createRouter() router.matcher = newRouter.matcher } export default router Copy Code
2. store/permission.js (maintains a state in vuex to control menu display by matching roles)
import { asyncRoutes, constantRoutes } from '@/router' // This method is used to match roles to route.meta.role s function hasPermission(roles, route) { if (route.meta && route.meta.roles) { return roles.some(role => route.meta.roles.includes(role)) } else { return true } } // This method traverses routes recursively, giving privileged routes to traverse export function filterAsyncRoutes(routes, roles) { const res = [] routes.forEach(route => { const tmp = { ...route } if (hasPermission(roles, tmp)) { if (tmp.children) { tmp.children = filterAsyncRoutes(tmp.children, roles) } res.push(tmp) } }) return res } const state = { routes: [], addRoutes: [] } const mutations = { SET_ROUTES: (state, routes) => { // This place maintains two states: addRouters and routes. state.addRoutes = routes state.routes = constantRoutes.concat(routes) } } const actions = { generateRoutes({ commit }, roles) { return new Promise(resolve => { let accessedRoutes if (roles.includes('admin')) { accessedRoutes = asyncRoutes || [] } else { // Core code that matches routes and acquired roles (background acquired) accessedRoutes = filterAsyncRoutes(asyncRoutes, roles) } // Route the matched permissions to set into vuex commit('SET_ROUTES', accessedRoutes) resolve(accessedRoutes) }) } } export default { namespaced: true, state, mutations, actions } Copy Code
3. src/permission.js (create a new routing guard function, either in main.js or pull out a file)
The main code here is to check which routes are accessible before controlling route jumps. Logic for jumps after login can be written here
// permission.js router.beforeEach((to, from, next) => { if (store.getters.token) { // Determine whether there is a token if (to.path === '/login') { next({ path: '/' }); } else { // Determine if the current user has pulled out user_info information if (store.getters.roles.length === 0) { store.dispatch('GetInfo').then(res => { // Pull info const roles = res.data.role; // Match the role s you get in to generate accessible routes store.dispatch('GenerateRoutes', { roles }).then(() => { // Dynamically add accessible routing tables (core code, nothing to do without it) router.addRoutes(store.getters.addRouters) // The hack method ensures that addRoutes are complete next({ ...to, replace: true }) }) }).catch(err => { console.log(err); }); } else { next() //When user privileges are available, all accessible routes are generated. If access is not privileged, full access will automatically go to page 404 } } } else { if (whiteList.indexOf(to.path) !== -1) { // Enter directly from the logon-free whitelist next(); } else { next('/login'); // Otherwise redirect all to login page } } }) Copy Code
4. Sidebar can take data from vuex for rendering
The core code is to render the sidebar by taking usable routing objects from the router, whether it is a front-end dynamic load or a back-end dynamic load route.
layout/components/siderbar/index.vue
<el-menu :default-active="activeMenu" :collapse="isCollapse" :background-color="variables.menuBg" :text-color="variables.menuText" :unique-opened="false" :active-text-color="variables.menuActiveText" :collapse-transition="false" mode="vertical" > // Loop the route fetched as a parameter to the subcomponent <sidebar-item v-for="route in routes" :key="route.path" :item="route" :base-path="route.path" /> </el-menu> // Get privileged routes routes() { return this.$router.options.routes } Copy Code
layout/components/siderbar/siderbarItem.vue
<template slot="title"> <item v-if="item.meta" :icon="item.meta && item.meta.icon" :title="item.meta.title" /> </template> <sidebar-item v-for="child in item.children" :key="child.path" :is-nest="true" :item="child" :base-path="resolvePath(child.path)" class="nest-menu" /> props: { // route object item: { type: Object, required: true }, isNest: { type: Boolean, default: false }, basePath: { type: String, default: '' } } Copy Code
The front-end controls the route, and the logic is relatively simple. The back-end only needs to store the user's role. The front-end matches the user's role.But if you add a new role, it will be very painful, and each will be added.
2. Backend Control Routing
Back-end control routing is the solution for most back-end management systems. Our company also manages routing in this way.The specific ideas are as follows:
1. After a user logs in, the backend generates accessible routing data directly based on the user's role, noting that this is the data 2. Front-end converts the routing data returned by the back-end into the routing structure it needs. Copy Code
Specific code logic:
1. There are only some static routes in router.js, such as login, 404, etc. 2. Organize a data structure and store it in a table 3. Get routing data from the backend, write a data conversion method, talk about data into accessible routes 4. It also maintains a vuex state to store the converted routes inside the vuex 5. Sidebar is also rendering data from routes Copy Code
Because most of the processes behind the front-end control and back-end control are the same, this place only looks at the different processes ahead:
1. store/permission.js, send a request to get data in vuex
GenerateRoutes({ commit }, data) { return new Promise((resolve, reject) => { getRoute(data).then(res => { // Convert the obtained data and save it in vuex const accessedRouters = arrayToMenu(res.data) accessedRouters.concat([{ path: '*', redirect: '/404', hidden: true }]) commit('SET_ROUTERS', accessedRouters) resolve() }).catch(error => { reject(error) }) }) } Copy Code
2. Organize a data structure and store it in a table
We know that the data structure specified by vue's router is as follows:
{ path: '/form', component: Layout, children: [ { path: 'index', name: 'Form', component: () => import('@/views/form/index'), meta: { title: 'Form', icon: 'form' } } ] } Copy Code
Therefore, there are several parameters for the first-level menu: id, path, name, component, title. The second-level menu children is an array and the relationship between the child and the parent, so you can add a fid or parentId to match, which will be explained in detail when you write the conversion method later. The data format is probably like this:
// Level 1 Menu // A parentId of 0 serves as a first-level menu, with an id of 4 digits, so you'll know why when you develop your project { id: 1300 parentId: 0 title: "Business management" path: "/enterprise" hidden: false component: null hidden: false name: "enterprise" }, // Level 2 Menu // If the parentId is not zero, you can match the parentId with the id of the first-level menu. push on the matching is inside the child ren { id: 1307 parentId: 1300 title: "Business Information" hidden: false path: "merchantInfo" component: "enterprise/merchantInfo" // To match the local file address hidden: false name: "merchantInfo" } Copy Code
3. Write a transformation method to convert the obtained data into a router structure
The data just obtained cannot be directly converted to router for rendering. It needs a method of arrayToMenu. I have just said some ideas. Let's analyze this method together:
export function arrayToMenu(array) { const nodes = [] // Get Top Node for (let i = 0; i < array.length; i++) { const row = array[i] // This exists method is to determine if there are children if (!exists(array, row.parentId)) { nodes.push({ path: row.path, // Routing Address hidden: row.hidden, // true for all ports, if backend does not match component: Layout, // Typically, it's the component that matches your file name: row.name, // Route Name meta: { title: row.title, icon: row.name }, // title is the name displayed id: row.id, // id of the route redirect: 'noredirect' }) } } const toDo = Array.from(nodes) while (toDo.length) { const node = toDo.shift() // Get Child Nodes for (let i = 0; i < array.length; i++) { const row = array[i] // parentId equals the id of the parent, push to which if (row.parentId === node.id) { const child = { path: row.path, name: row.name, hidden: row.hidden, // Core code because the component of the secondary route needs to match the page component: require('@/views/' + row.component + '/index.vue'), meta: { title: row.title, icon: row.name }, id: row.id } if (node.children) { node.children.push(child) } else { node.children = [child] } toDo.push(child) } } } return nodes } // See if there are children function exists(rows, parentId) { for (let i = 0; i < rows.length; i++) { if (rows[i].id === parentId) return true } return false } Copy Code
Sidebar code is the same as static code, so don't say it again
summary
Is dynamic routing well controlled at the front end or at the back end?We can only say that each has its own advantages, after all, the business scenarios are different, so you can try them first.There are many other areas of code that need to be optimized. Every God is welcome to criticize and correct them.
Personal Public Number: Little Jerry says
Also welcome to follow my Personal Public Number and share some interesting front-end knowledge.