当前位置: 首页 > Web前端 > vue.js

vue动态路由权限管理

时间:2023-03-31 14:48:28 vue.js

动态路由设置一般有两种:(1)、简单角色路由设置:比如只涉及管理员和普通用户的权限。通常简单的角色权限设置(2)和复杂的路由权限设置直接在前端进行:比如OA系统,多个角色的权限配置。通常后端需要返回路由列表,前端渲染使用1.简单角色路由设置(1)配置项目路由权限//router.jsimportVuefrom'vue'importRouterfrom'vue-router'importLayoutfrom'@/layout'Vue.use(Router)letasyncRoutes=[{path:'/permission',component:Layout,redirect:'/permission/page',alwaysShow:true,name:'Permission',meta:{title:'Permission',roles:['admin','editor']//普通用户角色},children:[{path:'page',component:()=>import('@/views/permission/page'),name:'PagePermission',meta:{title:'Page',roles:['editor']//只有具有编辑角色的用户才能访问此页面}},{path:'role',component:()=>import('@/views/permission/role'),name:'RolePermission',meta:{title:'Role',roles:['admin']//只有具有admin角色的用户才能访问此页面}}]},]letrouter=newRouter({mode:'history',scrollBehavior:()=>({y:0}),routes:asyncRoutes})exportdefaultrouter(2)createanewpublicasyncRouter.jsfile//asyncRouter.js//判断当前角色是否有访问权限functionhasPermission(roles,route){if(route.meta&&route.meta.roles){returnroles.some(role=>route.meta.roles.includes(role))}else{returntrue}}//递归过滤异步路由表,过滤角色权限路由exportfunctionfilterAsyncRoutes(路线,角色){constres=[];routes.forEach(route=>{consttmp={...route}if(hasPermission(roles,tmp)){if(tmp.children){tmp.children=filterAsyncRoutes(tmp.children,roles)}res.push(tmp)}})returnres}(3)创建路由守卫:创建一个publicpermission.js文件并设置路由守卫importrouterfrom'./router'importstorefrom'./store'importNProgressfrom'nprogress'//进度条插件import'nprogress/nprogress.css'//进度条样式mport{getToken}from'@/utils/auth'import{filterAsyncRoutes}from'@/utils/asyncRouter.js'NProgress.configure({showSpinner:false})//进度条配置constwhiteList=['/login']router.beforeEach(async(to,from,next)=>{//进度条开始NProgress.start()//获取路由元中的标题,设置为页面标题document.title=to.meta.title//获取用户登录的tokenconsthasToken=getToken()//判断当前用户是否登录if(hasToken){if(to.path==='/login'){next({path:'/'})NProgress.done()}else{//从存储中获取用户角色consthasRoles=store.getters.roles&&store.getters.roles.length>0if(hasRoles){next()}else{try{//获取用户角色constroles=awaitstore.state.roles//通过用户角色获取角色路由表constaccessRoutes=filterAsyncRoutes(awaitstore.state.routers,roles)//动态添加路由到路由器router.addRoutes(accessRoutes)next({...to,replace:true})}catch(error){//清除用户登录信息后,跳回登录页面next(`/login?redirect=${to.path}`)NProgress.done()}}}}else{//用户没有登录if(whiteList.indexOf(to.path)!==-1){//需要跳转的路由是否是白名单中的路由,如果是,直接next()}else{//要跳转的路由不是白名单中的路由,直接跳转到登录页面next(`/login?redirect=${to.path}`)//结束精度栏NProgress.done()}}})router.afterEach(()=>{//结束精度栏NProgress.done()})(4)在main.js中引入permission.js文件(5)登录时在store中存储角色。2.复杂的路由权限设置(后台动态返回路由数据)(1)配置项目路由文件。该文件中没有路由,或者存在一部分公共路由,即没有权限的路由importVuefrom'vue'importRouterfrom'vue-router'importLayoutfrom'@/layout';Vue.use(Router)//配置项目exportconstc中没有涉及权限的公共路由instantRoutes=[{path:'/login',component:()=>import('@/views/login'),hidden:true},{path:'/404',component:()=>import('@/views/404'),hidden:true},]constcreateRouter=()=>newRouter({mode:'history',scrollBehavior:()=>({y:0}),routes:constantRoutes})constrouter=createRouter()exportfunctionresetRouter(){constnewRouter=createRouter()router.matcher=newRouter.matcher}exportdefaultrouter(2)新建一个publicasyncRouter.js文件//导入公共路由如路由文件import{constantRoutes}from'../router';//Layout组件是项目中的主页面,切换路由时只切换Layout中的组件importLayoutfrom'@/layout';exportfunctiongetAsyncRoutes(routes){constres=[]//定义路由中需要的自定义名称constkeys=['path','name','children','redirect','meta','hidden']//遍历路由数组重新组织可用Routes.forEach(item=>{constnewItem={};if(item.component){//判断item.componentt是否等于'Layout',如果是,直接替换为导入的Layout组件if(item.component==='Layout'){newItem.component=Layout}else{//item.component不等于为'Layout',则表示是组件的路径地址,所以直接换成路由引入的方法newItem.component=resolve=>require([`@/views/${item.component}`],resolve)//这里最好用require,import引入变量的时候会出现各种莫名其妙的错误//newItem.component=(()=>import(`@/views/${item.component}`));}}for(constkeyinitem){if(keys.includes(key)){newItem[key]=item[key]}}//如果当前遍历的路由有子路由,则需要递归遍历sub-routesif(newItem.children&&newItem.children.length){newItem.children=getAsyncRoutes(item.children)}res.push(newItem)})//返回处理后可用的路由数组returnres}(3)创建routeguards:创建publicpermission.js文件并设置routeguards//进度条导入设置同上面第一个说明importrouterfrom'./router'importstorefrom'./store'importNProgressfrom'nprogress'//progressbarimport'nprogress/nprogress.css'//progressbarstyleimport{getToken}from'@/utils/auth'//gettokenfromcookieimport{getAsyncRoutes}from'@/utils/asyncRouter'constwhiteList=['/login'];router.beforeEach(async(to,from,next)=>{NProgress.start()document.title=to.meta.title;//getuserstoken,用于判断当前用户是否登录consthasToken=getToken()if(hasToken){if(to.path==='/login'){next({path:'/'})NProgress.done()}else{//异步获取store中的路由letroute=awaitstore.state.addRoutes;consthasRouters=route&&route.length>0;//判断store中是否有路由,如果有,继续下一步if(hasRouters){next()}else{//store中没有路由,需要获取异步路由并格式化try{constaccessRoutes=getAsyncRoutes(awaitstore.state.addRoute小号);//动态添加格式化路由router.addRoutes(accessRoutes);next({...to,replace:true})}catch(error){//Message.error('发生错误')next(`/login?redirect=${to.path}`)NProgress.done()}}}}else{if(whiteList.indexOf(to.path)!==-1){next()}else{next(`/login?redirect=${to.path}`)NProgress.done()}}})router.afterEach(()=>{NProgress.done()})(4)在main.js中引入权限.js文件(5)在store中存储登录时的路由信息??。//调用登录接口后,调用路由接口,后台返回对应用户的路由res.router。我们需要存储在store中,方便其他地方取this.$store.dispatch("addRoutes",res.router);至此,整个动态路由就可以走通了,但是页面跳转和routeguard处理是异步的,添加动态路由后跳转是空白页面。这是因为路由在执行next()时,路由器中的数据并不存在。这时候可以通过window.location.reload()刷新路由后端返回的路由格式:routerList=[{"path":"/other","component":"Layout","redirect":"noRedirect","name":"otherPage","meta":{"title":"Test",},"children":[{"path":"a","component":"file/a","name":"a","meta":{"title":"apage","noCache":"true"}},{"path":"b","component":"file/b","name":"b","meta":{"title":"bpage","noCache":"true"}},]}]注:Vue是单页应用,所以一旦页面刷新,部分数据会丢失,所以我们需要将数据存储在store本地,保证路由不丢失关于vue页面刷新和保存页面状态,1.通过本地存储状态数据,页面刷新成功后再次从本地存储中读取状态数据//当vuex中的数据发生变化时,会触发localStorage的存储操作localstorage.setItem('state',JSON.stringify(this.$store.state))//获取页面加载时创建的本地存储中的数据localStorage.getItem('state')&&this.$store.replaceState(JSON.parse(localStorage.getItem('state')));注意:该操作会频繁触发localStorage的访问工作2.监听页面刷新触发访问操作。首先,在入口组件App.vue中创建的localstorage或sessionStorage中访问state中的数据//页面加载时读取sessionStorage中的状态信息if(sessionStorage.getItem('state')){this.$store.replaceState(Object.assign({},this.$store.state,JSON.parse(sessionStorage.getItem('state'))))}//页面刷新时将状态数据存入sessionStoragewindow.addEventListener('beforeunload',()=>{sessionStorage.setItem('state',JSON.stringify(this.$store.state))})注:Object.assign()方法用于从中复制所有可枚举属性的值一个或多个源对象到目标对象在ios端、安卓端、mac端的safair浏览器中可以正常访问,但是在ios端的safair浏览器中出现问题,无法获取数据页面刷新后。原因:ios端的beforeunload方法没有执行,导致本地没有存储state数据。查询ios官方文档,文档上说unload和beforeunload已经被丢弃,改用pagehide。window.addEventListener('pagehide',()=>{sessionStorage.setItem('state',JSON.stringify(this.$store.state))})这么改之后,在PC、Android、andiossides//Sessionhistoryeventpageshowevent:当用户访问页面时触发;pageshow事件类似于onload事件,第一次加载页面时触发onload事件,每次加载页面都会触发pageshow事件,即页面加载时不触发onload事件从浏览器缓存中读取。pagehide事件:当用户离开当前网页时触发;pagehide事件有时可以替代unload事件,但是触发unload事件后页面无法缓存。