v3+ts——3、路由模块(包含权限验证)

编程入门 行业动态 更新时间:2024-10-06 06:45:56

v3+ts——3、<a href=https://www.elefans.com/category/jswz/34/1771390.html style=路由模块(包含权限验证)"/>

v3+ts——3、路由模块(包含权限验证)

前言:路由的权限验证方式为后端返回权限标识字段,前端通过对权限标识字段进行验证,验证通过则显示相应的路由,不通过则不显示。因此将路由分为需要权限验证和不需要权限验证两种。

1、基础准备

(1)创建文件

文件介绍: 

router文件夹

  1. actionRouter.ts 需要权限验证的路由
  2. index.ts  路由入口
  3. staticRouter.ts  不需要权限验证的路由 任何人都可以访问

stores

  1.  permissionRouter.ts   验证路由权限相关的状态管理内容

 utils文件夹

  1.  router.ts   编写路由守卫

2、路由页面

views/home/index.vue(布局容器)

<template><div class="common-layout height100"><el-container class="height100"><el-aside width="200px"><!-- 侧边内容 --><sideBar /></el-aside><el-container><el-header><!-- 标题内容 --><headerBar/></el-header><el-main><!-- 内容主体 --><router-view></router-view></el-main></el-container></el-container></div>
</template><script setup lang="ts">
import headerBar from "@/components/headerBar/index.vue";
import sideBar from "@/components/sideBar/index.vue";</script>

staticRouter.ts文件

export default [{path: '/home',name: 'home',component:()=>import('@/views/home/index.vue'),//home中包含布局容器,如果是需要布局容器,就在最外层路由中加入这个component,如果不需要布局容器,就像下面的/login一样单独写在外面并在meta中加入 hidden:truemeta:{index:1,//标识是否为一级菜单},children:[{path: '/home/userDetails',component: () => import('@/views/testPool/index.vue'),meta:{title:'测试title-1'},},{path: '/home/abcd',component: () => import('@/views/testPool/index.vue'),meta:{title:'测试title-2'},},],},{path: '/login',name: 'login',component: () => import('@/views/login/index.vue'),meta:{hidden:true,// 标识是否在侧边栏菜单中展示}},
]

actionRouter.ts 文件

export default [{path: '/userlist',name: 'userlist',component:()=>import('@/views/home/index.vue'),meta:{index:1,title:'列表'},children:[{path: '/userlist/userlist1-1',name: 'userlist1-1',component: () => import('@/views/writerlist/index.vue'),meta:{perStr:'userlist页面Str',title:'写手列表',},},{path: '/userlist/userlist2-2',name: 'userlist2-2',component: () => import('@/views/userList/index.vue'),meta:{perStr:'userlist页面Str',title:'用户列表',},}],},{path: '/userDetails',component: () => import('@/views/testPool/index.vue'),meta:{hidden:true,perStr:'详情页面Str',},},]

index.ts文件

import { createRouter, createWebHistory } from 'vue-router'
import staticRouter from "./staticRouter";
import actionRouter from "./actionRouter";const router = createRouter({history: createWebHistory(import.meta.env.BASE_URL),routes: [// 首先加载无需权限验证的路由...staticRouter,{path:'/',component:()=>import('@/views/home/index.vue'),},]
})export const perRouter =  [    // 将需要验证的路由 以及404页面导出备用...actionRouter,{// 匹配之前路由未能匹配到的内容,也就是路由输入错误的情况,这个路由必须写在所有路由最后面path:'/:path(.*)',component:() => import('@/views/404/index.vue'),}
]
export default router

utils/Auth.ts 

import Cookies from 'js-cookie'
export const setToken = (token:string)=>{return Cookies.set('myToken', token, { expires: 1 })
}
export const getToken = ()=>{return Cookies.get('myToken')
}
export const removeToken = ()=>{//在存储用户信息时加一个通用前缀,在退出登录时即可通过这种方式批量删除for (const key in localStorage) {if(key.includes('xinba-')){ localStorage.removeItem(key)}}return Cookies.remove('myToken')
}

utils/router.ts(路由守卫-重要)

import router from "@/router/index";
import { setToken,getToken} from "@/utils/Auth";
import permissionRouter from '@/stores/permissionRouter'
let noTokenRouter = ['/login']
router.beforeEach(async(to,form,next)=>{// 如果是白名单路由,直接放行 主要用于一些无需登录页面,例如登录注册if(noTokenRouter.includes(to.path))next()// 如果没有token 直接去登录页let myToken = getToken()if(!myToken)next({path:'/login'})// 引入验证权限的状态管理const myPerStore = permissionRouter()// perRouterFlag 标识是否已经加载过需要权限验证的路由,false为未加载,就进行验证权限然后添加路由if(!myPerStore.perRouterFlag){// addRouteFn() 是状态管理中的 获取有权限的路由的方法 最后返回结果为通过验证的路由const addRouterList =  await myPerStore.addRouteFn()addRouterList.forEach(item=>{router.addRoute(item)})// 通过next({...to}) 重新跳转到当前路由。如果这一步不重新跳转,就会导致在新添加的路由刷新页面时页面会为空next({...to})}else{// 如果已经加载过路由,就正常跳转next()}
})export default router

stores/permissionRouter.ts(权限状态管理-核心)

import { ref, computed, reactive } from 'vue'
import { defineStore } from 'pinia'
import {perRouter} from '@/router/index' //引入需要权限验证的路由
import type { RouteRecordRaw } from 'vue-router'// 验证权限的方法 参数为 权限标识数组,路由数组
function filterRoute(permissionArr:string[],routerList:RouteRecordRaw[]){let newRouter:RouteRecordRaw[] = reactive([])routerList.forEach((item:RouteRecordRaw)=>{// 如果不包含 perStr ,说明不需要权限验证,可以直接显示// 如果包含,就验证改perStr是否在返回的权限列表里if(!item?.meta?.perStr||permissionArr.includes(item.meta.perStr as string)){if(item.children){// 如果有child,就递归调用item.children = filterRoute(permissionArr,item.children)}newRouter.push(item)}})return newRouter
}export default defineStore('permission', () => {let permissionArr:string[] = reactive([]) // 存放权限标识的数组let perRouterFlag = ref(false); //路由是否加载完成// 验证路由权限的方法async function addRouteFn(){// 获取本地储存的权限标识,如果没有就调接口获取let catchUserPermission = JSON.parse(localStorage.getItem('xinba-userPermission')||"[]")if(catchUserPermission.length>0){catchUserPermission.forEach((item:string)=>{permissionArr.push(item)})perRouterFlag.value = true;//获取完成之后将这个值设置为 true,表示路由已经获取完成了}else{//调接口获取权限列表['userlist页面Str'].forEach((item:string)=>{permissionArr.push(item)})perRouterFlag.value = true;//获取完成之后将这个值设置为 true,表示路由已经获取完成了localStorage.setItem('xinba-userPermission',JSON.stringify(permissionArr))}return filterRoute(permissionArr,perRouter)}return { addRouteFn,perRouterFlag }
})

3、侧边栏效果实现

components/sideBar/checkPermission.ts

import router from '@/router';
import type { RouteRecordRaw } from 'vue-router'
type RouArr = RouteRecordRaw[]
// 过滤掉路由中的meta:{hidden:true}
function filterRouter(router:RouArr):RouArr{return router.filter((item:RouteRecordRaw)=>{// 如果hidden为true,返回false,过滤掉if(item.meta?.hidden)return false// 如果有child,继续递归调用if(item.children&&item.children.length>0){item.children = filterRouter(item.children)return {...item}}else{return [item]}})
}
const allRouter = router.getRoutes()export const routerArr = filterRouter(allRouter.filter(item=>item.meta.index==1))

components/sideBar/index.vue

<template><div class="side-box"><el-menu:default-active="defaultActive"class="el-menu-vertical-demo"router><template v-for="(route,index) in routerArr" :key="index"><el-sub-menu v-if="route.children&&route.children.length>0" :index="route.path"><template #title><el-icon><location /></el-icon><span>{{ route.name }}</span></template><el-menu-item  v-for="(item,i) in route.children" :key="i" :index="item.path">{{ item.meta?.title||'未知标题' }}</el-menu-item></el-sub-menu><el-menu-item v-else :index="route.path"><el-icon><Menu /></el-icon><span>{{ route.name }}</span></el-menu-item></template></el-menu></div>
</template><script setup lang="ts">
import { computed, reactive, ref } from "vue";
import { useRoute } from "vue-router";
import { routerArr } from "./checkPermission";
const myUseRoute = useRoute()const defaultActive = computed(()=>{return myUseRoute.path
})
</script>
<style lang="scss" scoped>
.side-box{height: 100%;.el-menu{height: 100%;}
}
</style>

页面效果

更多推荐

v3+ts——3、路由模块(包含权限验证)

本文发布于:2024-02-27 21:04:50,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1766787.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:路由   模块   权限   ts

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!