九步完成 vue-admin-template 动态渲染路由

这里使用的是 vue-admin-template 这个模板。可以从官网下载 vue-admin-template(基础模板)和 vue-template-admin(集成方案) 这两个模板,对照着修改。链接

1. 稍微整理一下页面

在这里插入图片描述
修改后台的路由文件 src/router/index.js

export const constantRoutes = [
  {
    
    
    path: '/login',
    component: () => import('@/views/login/index'),
    hidden: true
  },
  {
    
    
    path: '/404',
    component: () => import('@/views/404'),
    hidden: true
  },
  {
    
    
    path: '/',
    component: Layout,
    redirect: '/dashboard',
    children: [{
    
    
      path: 'dashboard',
      name: 'Dashboard',
      component: () => import('@/views/dashboard/index'),
      meta: {
    
     title: '首页', icon: 'dashboard' }
    }]
  }
]
// 动态路由
export const asyncRoutes = []
// 错误路由
export const errorRoutes = [
  // 404 page must be placed at the end !!!
  {
    
     path: '*', redirect: '/404', hidden: true }
]
const createRouter = () => new Router({
    
    
  // mode: 'history', // require service support
  scrollBehavior: () => ({
    
     y: 0 }),
  routes: constantRoutes
})

2. 制作菜单mock数据

在这里插入图片描述
在 mock/user.js 中新增

 // 获取左侧菜单导航
  {
    
    
    url: '/vue-admin-template/user/getMenuList',
    type: 'get',
    response: config => {
    
    
      return {
    
    
        code: 20000,
        data: {
    
    
          menu: [
            {
    
    
              path: '/admin',
              component: '#',
              redirect: '/roles',
              title: '管理员设置',
              icon: 'el-icon-s-help',
              children: [
                {
    
    
                  path: '/roles',
                  component: 'admin/roles',
                  title: '角色管理'
                },
                {
    
    
                  path: '/auth',
                  component: 'admin/auth',
                  title: '权限管理'
                }
              ]
            }
          ]
        }
      }
    }
  }

在 src\api\user.js 中
在这里插入图片描述

// 获取菜单的接口
export function getMenuList() {
    
    
  return request({
    
    
    url: '/vue-admin-template/user/getMenuList',
    method: 'get'
  })
}

3. 过滤路由

在 vue-template-admin 中,找到 src/store/modules/permission.js 文件,复制到自己的项目 vue-admin-template 中,就行修改,修改之后,自己对比这看

import {
    
     asyncRoutes, constantRoutes } from '@/router'
import Layout from '@/layout' // 布局组件
import {
    
     firstUpperCase } from '@/utils' // 处理单词首字母大写的方法
import {
    
     getMenuList } from '@/api/user' // 获取菜单的方法

/**
 * Use meta.role to determine if the current user has permission
 * @param roles
 * @param route
 */
function hasPermission(roles, route) {
    
    
  if (route.meta && route.meta.roles) {
    
    
    return roles.some(role => route.meta.roles.includes(role))
  } else {
    
    
    return true
  }
}

/**
 * Filter asynchronous routing tables by recursion
 * @param routes asyncRoutes
 * @param roles
 */
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
}
// 过滤获取到的菜单
export function generaMenu(routes, data) {
    
    
  // console.log(routes);
  let menu
  data.forEach(item => {
    
    
    menu = {
    
    
      path: item.path,
      name: firstUpperCase(item.path.substr(1)), // 单词首字母大写
      component: item.component === '#' ? Layout : (resolve) => require([`@/views/${
      
      item.component}`], resolve),
      children: [],
      redirect: `${
      
      item.redirect}`,
      meta: {
    
     title: item.title, icon: item.icon }
    }
    // 解决后台返回的数据 子级路由没有重定向这一属性
    if (menu.redirect === 'undefined') {
    
    
      delete menu.redirect
      menu.meta.icon = 'el-icon-menu'
    }
    if (item.children) {
    
    
      menu.children.map(v => delete v.redirect)
      generaMenu(menu.children, item.children)
    }
    routes.push(menu)
  })
}
const state = {
    
    
  routes: [],
  addRoutes: []
}

const mutations = {
    
    
  SET_ROUTES: (state, routes) => {
    
    
    state.addRoutes = routes
    state.routes = constantRoutes.concat(routes)
  }
}

const actions = {
    
    
  generateRoutes({
    
     commit }, roles) {
    
    
    return new Promise(async (resolve) => {
    
    
      const loadMenuData = []
      let menuList = []
      // 从本地缓存获取菜单
      const menuRouter = JSON.parse(localStorage.getItem('menuList'))
      // 如果没有就发送请求获取菜单
      if (!menuRouter) {
    
    
        const res = await getMenuList()
        // console.log(res)
        menuList = res.data.menu
        // 将菜单存入本地缓存
        localStorage.setItem('menuList', JSON.stringify(menuList))
      } else {
    
    
        // 如果本地缓存有,就直接从本地缓存获取
        menuList = menuRouter
      }
      Object.assign(loadMenuData, menuList)
      // 将获取到的菜单格式化成标准的路由格式
      generaMenu(asyncRoutes, loadMenuData)
      let accessedRoutes
      if (roles.includes('admin')) {
    
    
        accessedRoutes = asyncRoutes || []
      } else {
    
    
        accessedRoutes = filterAsyncRoutes(asyncRoutes, roles)
      }
      commit('SET_ROUTES', accessedRoutes)
      resolve(accessedRoutes)
    })
  }
}

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

注意点

  1. 在 src/store/getters.js 文件中,引入 roles: state => state.user.roles, 和 permission_routes: state => state.permission.routes
    在这里插入图片描述
  1. 一定要在 src/store/index.js 文件中引入 import permission from ‘./modules/permission’
    在这里插入图片描述

4. 添加路由

在 vue-template-admin 中,找到 src/permission.js 文件,复制到自己的项目 vue-admin-template 中,找到 src/permission.js 文件就行修改,修改之后,自己对比这看

import router from './router'
import store from './store'
import {
    
     Message } from 'element-ui'
import NProgress from 'nprogress' // progress bar
import 'nprogress/nprogress.css' // progress bar style
import {
    
     getToken } from '@/utils/auth' // get token from cookie
import getPageTitle from '@/utils/get-page-title'
import {
    
     errorRoutes } from '@/router'

NProgress.configure({
    
     showSpinner: false }) // NProgress Configuration

const whiteList = ['/login'] // no redirect whitelist

router.beforeEach(async(to, from, next) => {
    
    
  // start progress bar
  NProgress.start()

  // set page title
  document.title = getPageTitle(to.meta.title)

  // determine whether the user has logged in
  const hasToken = getToken()

  if (hasToken) {
    
    
    if (to.path === '/login') {
    
    
      // if is logged in, redirect to the home page
      next({
    
     path: '/' })
      NProgress.done()
    } else {
    
    
      const hasRoles = store.getters.roles && store.getters.roles.length > 0
      if (hasRoles) {
    
    
        next()
      } else {
    
    
        try {
    
    
          // get user info
          const {
    
     roles } = await store.dispatch('user/getInfo')
          let accessRoutes
          accessRoutes = await store.dispatch('permission/generateRoutes', roles)
          accessRoutes = accessRoutes.concat(errorRoutes)
          // console.log(accessRoutes)
          router.addRoutes(accessRoutes)
          next({
    
     ...to, replace: true })
        } catch (error) {
    
    
          // remove token and go to login page to re-login
          await store.dispatch('user/resetToken')
          Message.error(error || 'Has Error')
          next(`/login?redirect=${
      
      to.path}`)
          NProgress.done()
        }
      }
    }
  } else {
    
    
    /* has no token*/

    if (whiteList.indexOf(to.path) !== -1) {
    
    
      // in the free login whitelist, go directly
      next()
    } else {
    
    
      // other pages that do not have permission to access are redirected to the login page.
      next(`/login?redirect=${
      
      to.path}`)
      NProgress.done()
    }
  }
})

router.afterEach(() => {
    
    
  // finish progress bar
  NProgress.done()
})

5. 替换成要渲染的路由

在 src/layout/components/Sidebar/index.vue 文件中,修改这段代码
在这里插入图片描述

6. 退出登录,清空本地存储

在这里插入图片描述

async logout() {
    
    
      await this.$store.dispatch('user/logout')
      console.log(this.$store.getters.permission_routes)
      this.$router.push(`/login?redirect=${
      
      this.$route.fullPath}`)
      // 清空本地存储 - 清除路由
      localStorage.clear()
      // 退出后刷新页面,防止从新登录重复菜单 - 此方法不是很完美
      // 如果有更好的方法,可以在评论中提出
      location.reload()
    }

7. 添加页面 - (不要忘了)

在这里插入图片描述

8. 效果图

在这里插入图片描述

9. 完成。。。

猜你喜欢

转载自blog.csdn.net/m0_49045925/article/details/118531176
今日推荐