Vue实现路由权限及按钮级权限
地址:https://www.aliyundrive.com/s/ZDPUMQPhjc5
安装下依赖(yarn 或 npm i),直接yarn dev 或者 npm run dev 即可运行
分了两个角色,admin和vip
首先我自己模拟的后台json数据
这个是管理员的,有子菜单的就不写component
let userInfo = {name: '坤坤',token: 'token XXX',role: 'admin',menu: [{path: '/about',name: 'about',children: [{path: '/dance',name: 'dance',component: 'Dance'},{path: '/rap',name: 'rap',children: [{path: '/basketball',name: 'basketball',children: [{path: '/weiweiwei',name: 'weiweiwei',component: 'Test'},{path: '/weiweiwei2',name: 'weiweiwei2',component: 'Test'},]}]}]},{path: '/sing',name: 'sing',component: 'Sing'}]
}export default userInfo
这个是vip的,有子菜单的就不写component
let userInfo = {name: '张三',token: 'token XXX',role: 'vip',menu: [{path: '/about',name: 'about',component: 'About'},{path: '/sing',name: 'sing',component: 'Sing'}]
}export default userInfo
路由配置(配置了共有的页面,所有的动态路由,都添加到home的children里面)
import { createRouter, createWebHistory } from 'vue-router'
import HomeView from '../views/HomeView.vue'const router = createRouter({history: createWebHistory(import.meta.env.BASE_URL),routes: [{path: '/',name: 'home',component: HomeView,redirect: '/sing',children: [{path: '/sing',name: 'sing',component: () => import('../views/Sing.vue')}]},{path: '/login',name: 'login',component: () => import('../views/Login.vue')},{path: '/:pathMatch(.*)',name: 'notfound',component: () => import('../views/NotFound/index.vue')}]
})// 处理菜单,一会动态添加路由用
function getMenu(menu) {let newMenu = menu?.map(item => {return {path: item.path,name: item.name,component: item.component ? () => import(`../views/${item.component}.vue`) : '',children: getMenu(item.children)}})return newMenu
}
let newMenu = getMenu(JSON.parse(localStorage.getItem('userInfo'))?.menu)
newMenu?.forEach(item => {router.addRoute('home', item)
})router.beforeEach((to, from, next) => {if (to.path === '/login') {next()} else {let token = localStorage.getItem('token')if (!token) {next('/login')} else {// 只有从login页面过来的,才执行下面操作(不然每次路由跳转都执行,不太好)if (from.path === '/login') {// 从本地拿数据,并动态添加到路由上let newMenu = getMenu(JSON.parse(localStorage.getItem('userInfo'))?.menu)newMenu?.forEach(item => {router.addRoute('home', item)})}next()}}
})export default router
登录页(把个人信息和token全存到本地中)
<template><div class="login"><el-form :model="form" label-width="60px"><el-form-item label="用户名"><el-input v-model="form.name" /></el-form-item><el-form-item><el-button type="primary" @click="onSubmit">登录</el-button></el-form-item></el-form></div>
</template><script setup>
import { reactive } from 'vue'
import kunkun from '../data/kunkun'
import zhangsan from '../data/zhangsan'
import { useRouter } from 'vue-router'const userouter = useRouter()const form = reactive({name: '',
})const onSubmit = () => {if (form.name === '坤坤') {localStorage.setItem('userInfo',JSON.stringify(kunkun))localStorage.setItem('token',kunkun.token)userouter.push('/')}if (form.name === '张三') {localStorage.setItem('userInfo',JSON.stringify(zhangsan))localStorage.setItem('token',zhangsan.token)userouter.push('/')}
}
</script><style lang="scss" scoped>
.login {width: 300px;height: 100px;background-color: pink;margin: 10px auto;
}
</style>
首页(向循环组件传递路由数据)
<template><div class="common-layout"><el-container><el-aside width="200px"><MenuTree :MenuData="MenuData"></MenuTree></el-aside><el-container><el-header><span>Header</span><div><span>{{ uname }} --- {{ role }}</span><el-button @click="goback">退出</el-button></div></el-header><el-main><RouterView /></el-main></el-container></el-container></div>
</template><script setup>
import { useRouter } from "vue-router";
import MenuTree from "../components/MenuTree.vue";const userouter = useRouter();let MenuData = JSON.parse(localStorage.getItem("userInfo"))?.menu;let uname = JSON.parse(localStorage.getItem("userInfo"))?.name;
let role = JSON.parse(localStorage.getItem("userInfo"))?.role;const goback = () => {localStorage.clear();userouter.replace("/login");
};
</script><style scoped lang="scss">
.el-aside {height: 100vh;background-color: pink;
}.el-header {display: flex;justify-content: space-between;background-color: skyblue;
}
</style>
无限菜单组件(如果有children,就把数据传输,再调用自身)
<template><el-menu:default-active="useroute.fullPath"v-for="item in MenuData":key="item.path"router><el-menu-item :index="item.path" v-if="!item.children"><span>{{ item.name }}</span></el-menu-item><el-sub-menu :index="item.path" v-else><template #title><span>{{ item.name }}</span></template><MenuTree :MenuData="item?.children" /></el-sub-menu></el-menu>
</template><script setup>
import { defineProps } from "vue";
import { useRoute } from "vue-router";const useroute = useRoute();let { MenuData } = defineProps({MenuData: {default: [],type: Array,required: true,},
})
</script>
首页展示的二级菜单(根据角色渲染标签,就实现按钮级的权限)
<template><h2>sing</h2><el-button v-if="role === 'vip'">vip才显示</el-button><el-button v-if="role === 'admin'">admin才显示</el-button>
</template><script setup>
let role = JSON.parse(localStorage.getItem('userInfo'))?.role
</script><style scoped>
</style>