以vue2项目为例,动态路由,左侧侧边栏

(1)路由表的创建,包含静态路由与动态路由
在这里插入图片描述

/src/router/index.js

import Vue from 'vue'
import VueRouter from 'vue-router'
import {constantRouterMap} from './routes'

Vue.use(VueRouter)

const originalPush = VueRouter.prototype.push
VueRouter.prototype.push = function push(location) {
  return originalPush.call(this,location).catch(err => err)
}

const createRouter = () => new VueRouter({
  mode: 'history',
  scrollBehavior: () => ({
    y: 0
  }),
  routes:constantRouterMap
})
const router = createRouter()

export function resetRouter() {
  const newRouter = createRouter()
  router.matcher = newRouter.matcher // reset router
}

export default router
/src/router/routes.js

import commonLayout from '../layout/index.vue'

// 静态路由设置
export const constantRouterMap = [
    {
        path:'/',
        component:commonLayout,
        redirect: '/home',
        meta:{
            title:'',
            icon:'el-icon-house',
            hidden:false
        },
        children:[
            {
                path:'/home',
                component:() => import('@/views/home/index.vue'),
                meta:{
                    title:'首页',
                    icon:'el-icon-house',
                    hidden:false
                }
            }
        ]
    },
    {
        path:'/login',
        name:'login',
        component:() => import('@/views/login/index.vue'),
        hidden:true
    },
    {
        path:'/404',
        name:'404',
        component:() => import('@/views/404/index.vue'),
        hidden:true
    }
]

// 登录成功,获取用户身份信息,动态添加路由
export const asyncRoutes = [
    {
        path:'/user',
        name:'user',
        component:commonLayout,
        redirect:'/user/role',
        meta:{
            title:'用户管理',
            icon:'el-icon-user',
            roles: ['admin']
        },
        children:[
            {
                path:'/user/role',
                name:'role',
                component:() => import('@/views/user/roleManagement/index.vue'),
                meta:{
                    title:'角色管理',
                    icon:'el-icon-user',
                    roles: ['admin']
                }
            },
            {
                path:'/user/permission',
                name:'permission',
                component:() => import('@/views/user/perManagement/index.vue'),
                meta:{
                    title:'权限管理',
                    icon:'el-icon-lock',
                    roles: ['admin']
                }
            }
        ]
    },
    {
        path:'/product',
        name:'product',
        component:commonLayout,
        meta:{
            title:'商品管理',
            icon:'el-icon-tickets',
            roles:['admin','operate']
        }
    },
    {
        path: '*',
        redirect: '/404',
        hidden: true
    }
]

(2)动态路由思路:登录成功获取token-获取用户信息,根据meta.roles筛选路由表
在src下创建permission.js

import NProgress from "nprogress";
import 'nprogress/nprogress.css';
import { Message } from 'element-ui';
import { GET_TOKEN } from '@/utils/token';
import router from './router'
import store from './store'
NProgress.configure({showSpinner:false});

const whiteList = ['/login', '/404'] // 不重定向白名单
router.beforeEach(async (to, from, next) => {
    NProgress.start()
    let token = GET_TOKEN()
    if (token) {
        if (to.path == '/login') {
            next({ path: '/' })
        } else {
            // 确定获取用户角色,筛选路由
            let roles = store.getters.roles && store.getters.roles.length > 0
            if (roles) {
                // 有用户权限时,则完成路由筛选
                next()
            } else {
                try {
                    // 获取用户权限
                    let res = await store.dispatch('user/getUserInfo')
                    const accessRoutes = await store.dispatch('permission/generateRoutes', res.roles)
                    router.options.routes = store.getters.permission_routes
                    // 动态添加路由
                    accessRoutes.forEach(route => {
                        router.addRoute(route)
                    })
                    next({
                        ...to,
                        replace: true
                    })
                } catch (error) {
                    // 退出登录
                    await store.dispatch('loginout')
                    Message.error('出现错误~请重新登录')
                    next(`/login?redirect=${to.path}`)
                    NProgress.done()
                }
            }
            next()
        }
    } else {
        // 未登录重定向
        if (whiteList.indexOf(to.path) !== -1) {
            next()
        } else {
            let redirect = router.currentRoute.query.redirect
            next({path: redirect || '/'})
            NProgress.done()
        }
    }
})

router.afterEach(() => {
    NProgress.done()
})

使用状态管理筛选路由

/src/module/permission.js

import { constantRouterMap,asyncRoutes } from '@/router/routes'

function hasPermission(route,roles){
    if(route.meta && route.meta.roles){
        return roles.some(role => route.meta.roles.includes(role))
    } else {
        return true
    }
}

export function filterAsyncRoutes(routes,roles) {
    let res = []
    routes.forEach(route => {
        let temp = {
            ...route
        }
        // 有权限,递归筛选路由
        if(hasPermission(route,roles)) {
            if(temp.children) {
                temp.children = filterAsyncRoutes(temp.children,roles)
            }
            res.push(temp)
        }
    })

    return res
}

const state = {
    routes:[],//全部路由
    addRoutes:[]//动态路由
}

const mutations = {
    SET_ROUTES: (state,routes) => {
        state.addRoutes = routes
        state.routes = constantRouterMap.concat(routes)
    }
}
// 根据角色筛选路由
const actions = {
    generateRoutes({commit},roles) {
        return new Promise((resolve,reject) => {
            let accessRoutes = []
            if(roles && roles.length > 0) {
                accessRoutes = filterAsyncRoutes(asyncRoutes,roles)
            }
            commit('SET_ROUTES',accessRoutes)
            resolve(accessRoutes)
        })
    }
}

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

侧边栏:获取状态管理下筛选后的路由routes

/layout/index.js页面

<template>
  <div class="common_layout">
    <div :class="[{isFold:fold},'layout_asider']">
      <Logo/>
      <el-menu
        :default-active="currentPath"
        background-color="#545c64"
        text-color="#ffffff"
        unique-opened
        router
        :collapse="fold"
      >
        <Menu :routes="permission_routes"/>
      </el-menu>
    </div>
    <div :class="[{isFold:fold},'layout_nav']">
      <Tabbar/>
    </div>
    <div :class="[{isFold:fold},'layout_container']">
      <Main/>
    </div>
  </div>
</template>

<script>
import { mapGetters } from 'vuex';
import Menu from './menu'
import Logo from'./logo'
import Tabbar from './tabbar'
import Main from './main'
export default {
  name:"layout",
  components:{ Menu,Logo,Tabbar,Main },
  data() {
    return {}
  },
  computed:{
    ...mapGetters([
      'permission_routes',
      'fold'
    ]),
    currentPath() {
      return this.$route.path
    }
  }
}
</script>

<style lang="less" scoped>
.common_layout{
  width: 100%;
  height: 100vh;
  .layout_asider{
    width: @base_asider_width;
    height: 100vh;
    background-color: @base_asider_background;
    overflow: auto;

    /deep/.el-menu{
      border: none;
    }
    &.isFold{
      width:@base_asider_minWidth;
    }
    /deep/.el-menu--collapse{
      .el-submenu__icon-arrow{
        display: none;
      }
    }
  }
  .layout_nav{
    width:calc(100% - @base_asider_width);
    height:@base_nav_height;
    position: fixed;
    top:0;
    left:@base_asider_width;
    border-bottom:1px solid #e4e7e9;
    &.isFold{
      width: calc(100% - @base_asider_minWidth);
      left: @base_asider_minWidth;
    }
  }
  .layout_container{
    width: calc(100% - @base_asider_width);
    height: calc(100vh - @base_nav_height);
    position: absolute;
    top: @base_nav_height;
    left: @base_asider_width;
    padding: 15px;
    &.isFold{
      width: calc(100% - @base_asider_minWidth);
      left: @base_asider_minWidth;
    }
  }
}
</style>
/src/menu/index.js页面

<template>
    <div>
        <div v-for="item in routes" :key="item.path">
            <template v-if="!item.children">
                <el-menu-item :index="item.path" v-if="!item.hidden">
                    <i :class="item.meta.icon"></i>
                    <template #title>
                        {{ item.meta.title }}
                    </template>
                </el-menu-item>
            </template>
            <template v-if="item.children && item.children.length === 1">
                <el-menu-item :index="item.children[0].path" v-if="!item.children[0].hidden">
                    <i :class="item.children[0].meta.icon"></i>
                    <template #title>
                        {{ item.children[0].meta.title }}
                    </template>
                </el-menu-item>
            </template>
            <template v-if="item.children && item.children.length > 1">
                <el-submenu :index="item.path" v-if="!item.hideen">
                    <template #title>
                        <i :class="item.meta.icon"></i>
                        <span>{{ item.meta.title }}</span>
                    </template>
                    <Menu :routes="item.children"/>
                </el-submenu>
            </template>
        </div>
    </div>
</template>

<script>
export default {
    name:"Menu",
    props:{
        routes:{
            type: Array,
            default: () => []
        }
    },
    data() {
        return {}
    },
}
</script>

<style lang="less" scoped>

</style>
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值