vue-router 基于后端permissions动态生成导航菜单的示
目录
- Vue.js
- 1、注册全局守卫
- 2、Vuex状态管理 全局缓存routes
- 3、路由拦截
- 4、路由菜单
- 5、递归菜单vue组件
Vue.js
- vue-router
- vuex
1、注册全局守卫
核心逻辑
1、token身份验证(后端) => token失效返回登录页面
2、获取用户权限
3、校验permissions,动态添加路由菜单
router.beforeResolve 注册一个全局守卫。和 router.beforeEach 类似,区别是在导航被确认之前,同时在所有组件内守卫和异步路由组件被解析之后,解析守卫就被调用。
router.beforeResolve(async (to, from, next) => { let hasToken = store.getters['User/accessToken'] if (!settings.loginInterception) hasToken = true if (hasToken) { if (to.path === '/auth/sign-in') { next({ path: '/' }) } else { const hasPermissions = store.getters['User/permissions'] && store.getters['User/permissions'].length > 0 if (hasPermissions) { next() } else { try { let permissions if (!constant.loginInterception) { // settings.js loginInterception为false时,创建虚拟权限 await store.dispatch('User/setPermissions', ['admin']) permissions = ['admin'] } else { permissions = await store.dispatch('User/getUserInfo') } let accessRoutes = [] accessRoutes = await store.dispatch('Routes/setRoutes', permissions) // 添加路由 router.addRoutes(accessRoutes) next({ ...to, replace: true }) } catch { await store.dispatch('User/resetAccessToken') } } } } else { if (settings.routesWhiteList.indexOf(to.path) !== -1) { next() } else { next('/auth/sign-in') } } document.title = getPageTitle(to.meta.title) })
settings.js 全局设置
export default { // 是否开启登录拦截 loginInterception: true, // 不经过token校验的路由 routesWhiteList: ['/auth/sign-in', '/auth/register', '/401', '/404'], }
2、Vuex状态管理 全局缓存routes
- state :对数据的全局存储
- getter: 可以理解为computed ,对数据进行计算
- mutations :对数据的同步更改
- actions:对数据的异步更改(实现异步操作)
- module: 将 store 分割成模块
/** * @author Alan * @description 路由拦截状态管理 */ import { asyncRoutes, constantRoutes } from '@/router' import { filterAsyncRoutes } from '@/Utils/handleRoutes' const state = () => ({ routes: [], partialRoutes: [] }) const getters = { routes: (state) => state.routes, partialRoutes: (state) => state.partialRoutes } const mutations = { setRoutes (state, routes) { state.routes = constantRoutes.concat(routes) }, setPartialRoutes (state, routes) { state.partialRoutes = constantRoutes.concat(routes) } } const actions = { async setRoutes ({ commit }, permissions) { const finallyAsyncRoutes = await filterAsyncRoutes( [...asyncRoutes], permissions ) commit('setRoutes', finallyAsyncRoutes) return finallyAsyncRoutes }, setPartialRoutes ({ commit }, accessRoutes) { commit('setPartialRoutes', accessRoutes) return accessRoutes } } export default { namespaced: true, state, getters, mutations, actions }
3、路由拦截
/** * @author Alan * @description 判断当前路由是否包含权限 * @param permissions * @param route * @returns {boolean|*} */ export function hasPermission (permissions, route) { if (route.meta && route.meta.permissions) { return permissions.some((role) => route.meta.permissions.includes(role)) } else { return true } } /** * @author Alan * @description 根据permissions数组拦截路由 * @param routes * @param permissions * @returns {[]} */ export function filterAsyncRoutes (routes, permissions) { const finallyRoutes = [] routes.forEach((route) => { const item = { ...route } if (hasPermission(permissions, item)) { if (item.children) { item.children = filterAsyncRoutes(item.children, permissions) } finallyRoutes.push(item) } }) return finallyRoutes }
4、路由菜单
/* * @author Alan * @description 公共路由 */ export const constantRoutes = [ { path: '/auth', name: 'auth1', component: AuthLayout, children: authChildRoutes('auth1'), hidden: true // 隐藏菜单 }, { path: '/', name: 'dashboard', component: VerticleLayout, meta: { title: 'Dashboard', name: 'sidebar.dashboard', is_heading: false, is_active: false, link: '', class_name: '', is_icon_class: true, icon: 'ri-home-4-line', permissions: ['admin'] }, children: childRoutes('dashboard') } ] /* * @author Alan * @description 异步路由 */ export const asyncRoutes = [ { path: '/menu-design', name: 'horizontal-dashboard', component: HorizantalLayout, meta: { title: 'Menu Design', name: 'sidebar.MenuDesign', is_heading: false, is_active: false, link: '', class_name: '', is_icon_class: true, icon: 'ri-menu-3-line', permissions: ['admin'] }, children: horizontalRoute('dashboard') }, { path: '/core', name: 'core', component: VerticleLayout, meta: { title: 'UI Elements', name: 'sidebar.uiElements', is_heading: false, is_active: false, class_name: '', link: '', is_icon_class: true, icon: 'ri-pencil-ruler-line', permissions: ['admin'] }, children: coreChildRoute('co韩国站群服务器http://www.558idc.com/krzq.htmlre') } ]
5、递归菜单vue组件
<template> <b-collapse tag="ul" :class="className" :visible="open" :id="idName" :accordion="accordianName"> <li v-for="(item,index) in items" :key="index" :class=" !hideListMenuTitle? 'p-0' : item.meta.is_heading ? 'iq-menu-title' :activeLink(item) && item.children ? 'active' : activeLink(item) ? 'active' : ''"> <template v-if="!item.hidden"> <i v-if="item.meta.is_heading && hideListMenuTitle" class="ri-subtract-line" /> <span v-if="item.meta.is_heading && hideListMenuTitle">{{ $t(item.meta.name) }}</span> <router-link :to="item.meta.link" v-if="!item.is_heading" :class="`iq-waves-effect ${activeLink(item) && item.children ? 'active' : activeLink(item) ? 'active' : ''}`" v-b-toggle="item.meta.name"> <i :class="item.meta.icon" v-if="item.meta.is_icon_class"/> <template v-else v-html="item.meta.icon"> </template> <span>{{ $t(item.meta.name) }}</span> <i v-if="item.children" class="ri-arrow-right-s-line iq-arrow-right" /> <small v-html="item.meta.append" v-if="hideListMenuTitle" :class="item.meta.append_class" /> </router-link> <List v-if="item.children" :items="item.children" :sidebarGroupTitle="hideListMenuTitle" :open="item.meta.link.name !== '' && activeLink(item) && item.children ? true : !!(item.meta.link.name !== '' && activeLink(item))" :idName="item.meta.name" :accordianName="`sidebar-accordion-${item.meta.class_name}`" :className="`iq-submenu ${item.meta.class_name}`" /> </template> </li> </b-collapse> </template> <script> import List from './CollapseMenu' // 自身组件 import { core } from '../../../config/pluginInit' export default { name: 'List', props: { items: Array, className: { type: String, default: 'iq-menu' }, open: { type: Boolean, default: false }, idName: { type: String, default: 'sidebar' }, accordianName: { type: String, default: 'sidebar' }, sidebarGroupTitle: { type: Boolean, default: true } }, components: { List }, computed: { hideListMenuTitle () { return this.sidebarGroupTitle } }, mounted () { }, methods: { activeLink (item) { return core.getActiveLink(item, this.$route.name) } } } </script>
到此这篇关于vue-router 基于后端permissions动态生成导航菜单的示例代码的文章就介绍到这了,更多相关vue-router permissions导航菜单内容请搜索hwidc以前的文章或继续浏览下面的相关文章希望大家以后多多支持hwidc!