Vue development practice is my best practice, not the best in the industry, only for your reference, this is a series of articles, but the release time and content is not fixed.

This section only describes how the front end associates the menu data provided by the back end with the front end route. The menu management and permission management in the service should be based on actual projects.

introduce

Normally, pages are linked to routes, but for users menu = route = page, so many front ends link menu data to route configuration, which is actually a very bad habit.

Menu data is actually business data, which is created and allocated by business personnel. Different people see different menus. For example, the menu is configured as follows:

├ ─ ─ commodity management / │ ├ ─ ─ commodity list │ ├ ─ ─ discount merchandise │ └ ─ ─ labels ├ ─ ─ group permissions / │ ├ ─ ─ staff management │ ├ ─ ─ rights management │ └ ─ ─ role management └ ─ ─ system Settings / ├ ─ ─ gm set └ ─ ─ menu managementCopy the code

In this kind of menu, operators usually only have the menu of commodity management, but with the complexity of the business, the level of the menu may also change.

Writing to death on the front end can be very inflexible and requires frequent releases, but linking routing configuration to menu data can be a disaster for front-end refactoring.

A lot of people do this by passing the routing configuration to the back end and registering routes dynamically, i.e. menu-level configuration = parent-child routing configuration

[{"path": "/users"."meta": {
      "icon": "user-manger"."title": "User Management"
    },
    "children": [{"path": "/users/search"."meta": {
          "title": "User List"}}]}]Copy the code

While it is possible to decouple the business menu from the route configuration, there is no doubt that the route configuration is coupled to the menu data.

Menu data is simply the data used by menu components, and the association with routing is only that the menu carries the routing address.

Best practices

The preferred approach is through the navigation guard, such as the vue-Router’s beforeEach hook.

Your route can be defined like this:

export default[{path: '/'.component: Welcome,
    // Meta supports adding data to route definitions for navigation guards
    https://router.vuejs.org/zh/guide/advanced/meta.html / / document
    meta: {
      title: 'welcome'.bypass: true.// No menu permissions are required}, {},path: '/goods/search'.component: () = > import(/* webpackChunkName: "goods" */ '@/views/goods/Search.vue'),
    meta: {
      title: 'List of Goods',}}, {path: '/ 403'.component: Forbidden,
    meta: {
      title: 'No access'.bypass: true.// No menu permissions are required}},]Copy the code

Your menu can be defined like this:

// The menu has nothing to do with routing, just pointing to a page via path
// The hierarchy can be nested indefinitely, or even at any level[{"id": "000"."parentId": null."icon": "goods"."text": "Commodity Management"."children": [{"id": "000001"."parentId": "000"."text": "List of Goods"."path": "/goods/search"}}]]Copy the code

Data is stored in VUEX for subsequent use

// src/store/index.js

import { Store } from 'vuex'

import { toTree } from '@zhengxs/js.tree'

// For vuEX best practices refer to the state Management section
const store = new Store {
  state: {
    sideMenu: [].// The sidebar menu
    menuPathMap: {} // Menu item mapping, used to query menus according to routing addresses
  },
  // The getters return function is actually a trick
  // Business can be decoupled from global state acquisition with the caching and response effects of getters
  getters: {
    getMenuItemByPath({ menuPathMap }) {
      // Returns a function for external calls
      // Avoid logic scattered throughout the application
      return path= > menuPathMap[path]
    },
     hasMenuItemInPath({ menuPathMap }) {
      return path= > path in menuPathMap
    }
  },
  mutations: {
    // Get the menu from the project itself
    // No explanation here
    initMenu(state, payload) {
      const menuPathMap = {}

      // Convert menu row structure data into tree data
      // To facilitate the use of menu components
      state.sideMenu = toTree(payload, {
        transform(item) {
          // The menu containing the path is stored in the object
          // For the convenience of path query later
          if (item['path']) {
            menuPathMap[item['path']] = item
          }

          return item
        },
      })

      state.menuPathMap = menuPathMap
    }
  }
}

export default store
Copy the code

Set up your navigation guard and check if you have menu permissions in the guard

import store from '@/store'

router.beforeEach((to, from, next) = > {
  // Skip routes that do not need to be judged
  // Bypass is a custom attribute. Where is it defined in the route configuration
  if (to.meta.bypass) return next()

  // Since getters returns a function, it can be called directly
  if (store.getters.hasMenuItemInPath(to.path)) return next()

  // Go to page 403
  return next({
    path: '/ 403'.// Record the jump address so that 403 page can write a refresh button to re-enter
    query: { redirect: to.fullPath },
  })
})
Copy the code

When configured, the sidebar menu is rendered and the user clicks on it as expected.

series

  • The routing configuration
  • Menu and Routing
  • Local Proxy scheme
  • Local Mock scheme