Vue中基于用户类型的条件标签路由实现优化方案问询
基于Pinia用户类型的标签式路由单一数据源优化方案
核心思路
把所有用户权限规则统一存放在路由的meta字段中作为唯一数据源,后续的路由过滤、重定向、组件权限判断全基于这个字段处理,彻底消除重复定义的问题。
1. 统一路由元信息定义
在路由配置里,给每个需要权限控制的路由(含父路由和子路由)的meta添加allowedRoles字段,明确该路由允许访问的用户类型:
const routes = [ { path: '/dashboard', component: () => import('@/layouts/MainLayout.vue'), meta: { allowedRoles: ['admin', 'editor'] }, // 父路由受众规则 children: [ { path: 'overview', component: () => import('@/views/DashboardOverview.vue'), meta: { allowedRoles: ['admin', 'editor'] } // 子路由受众规则 }, { path: 'settings', component: () => import('@/views/DashboardSettings.vue'), meta: { allowedRoles: ['admin'] } // 仅管理员可访问 } ] }, { path: '/guest', component: () => import('@/views/GuestPage.vue'), meta: { allowedRoles: ['guest'] } } ]
2. 统一路由过滤工具函数
写一个可复用的过滤函数,接收原始路由数组和当前用户类型,返回符合权限的路由列表,父路由、子路由统一用这个函数处理,避免两次过滤:
// @/utils/routeFilter.js import { useUserStore } from '@/stores/user' export function filterRoutes(routes) { const userStore = useUserStore() const currentRole = userStore.userType return routes.filter(route => { // 判断当前路由是否对应用户开放 const isRouteAllowed = route.meta?.allowedRoles?.includes(currentRole) // 递归过滤子路由 if (route.children && route.children.length) { route.children = filterRoutes(route.children) // 父路由若有符合权限的子路由则保留 return isRouteAllowed || route.children.length > 0 } return isRouteAllowed }) }
3. 复用重定向逻辑
在路由守卫里,基于统一的allowedRoles字段处理重定向,不用重复判断用户类型:
// @/router/index.js import { createRouter, createWebHashHistory } from 'vue-router' import { filterRoutes } from '@/utils/routeFilter' import { useUserStore } from '@/stores/user' const rawRoutes = [/* 原始路由配置 */] const router = createRouter({ history: createWebHashHistory(), routes: [] // 初始为空,后续动态添加过滤后的路由 }) router.beforeEach(async (to, from, next) => { const userStore = useUserStore() const currentRole = userStore.userType // 未认证则跳登录页 if (!currentRole) { return next('/login') } // 路由未初始化时,先过滤并添加路由 if (router.getRoutes().length === 0) { const filteredRoutes = filterRoutes(rawRoutes) filteredRoutes.forEach(route => router.addRoute(route)) // 重新触发当前路由导航 return next({ ...to, replace: true }) } // 判断当前路由是否允许访问 const isAllowed = to.meta?.allowedRoles?.includes(currentRole) if (isAllowed) { next() } else { // 根据用户类型跳转对应默认页 const defaultPath = currentRole === 'admin' ? '/dashboard/overview' : '/guest' next(defaultPath) } })
4. 组件内无需重复传参
组件内如果需要判断权限,直接从Pinia取用户类型,或者基于路由的meta字段,不用通过props重复传递:
<template> <div v-if="isAdmin">管理员专属内容</div> </template> <script setup> import { useUserStore } from '@/stores/user' import { useRoute } from 'vue-router' const userStore = useUserStore() const route = useRoute() // 方式1:直接用Pinia中的用户类型 const isAdmin = userStore.userType === 'admin' // 方式2:基于当前路由meta判断 const canAccessSettings = route.meta?.allowedRoles?.includes(userStore.userType) </script>
内容的提问来源于stack exchange,提问作者darkbasic
相关产品推荐
相关产品推荐

