vue-需求-权限管理
一、按钮权限
-
根据账号权限决定页面中的按钮是否显示
-
使用 vue 自定义指令来判断是否拥有按钮的权限
// (1) 全局注册组件
Vue.directive('arrowBtn', {
// inserted:被绑定元素插入父节点时调用 (仅保证父节点存在,但不一定已被插入文档中)。
inserted(el, binding) {
// (2) 从 vuex 获取角色拥有的的权限
const pointsArr = store.state.user.userInfo.roles.points // ['POINT-USER-UPDATE']
// (3) 根据传入的值判断是否拥有此按钮的权限
if (!pointsArr.includes(binding.value)) {
// (4) 如果没有该权限, 则移除该按钮
el.remove(el)
}
}
})
// 使用自定义指令
<el-button
v-arrowBtn="'POINT-USER-UPDATE'"
>编辑</el-button>
二、页面权限
获取拥有的页面权限
// 获取角色拥有的页面权限
const {
data: {
roles: { menus }
}
} = await store.dispatch('user/getInfo')
// 筛选有显示权限的页面
const filterRoutes = asyncRoutes.filter((item) => {
return menus.includes(item.children[0].name)
})
// 使用 router.addRoutes() 方法添加了动态路由数组但是没有显示到左侧菜单中
router.addRoutes(filterRoutes)
提示: 添加路由并不会触发新的导航。也就是说,除非触发新的导航,否则不会显示所添加的路由。
存储动态路由规则
// 合并静态路由和动态路由, 存储 routes 到 vuex
store.commit('user/setRoute', [...constantRoutes, ...filterRoutes])
<!-- 传入 siderBarItem 渲染菜单 -->
<sidebar-item
v-for="route in $store.state.user.filterRoutes"
:key="route.path"
:item="route"
:base-path="route.path"
/>
bug: 404 和 白屏
以上操作完毕后在需要权限的页面刷新会出现两个问题: 404 和 白屏
(1) 404
原因: 静态路由中的 404 页面路由规则中的 path: * 会在动态路由之前匹配
解决方案: 将404路由规则移到动态路由数组之后
// 先添加规则, 再添加404到router中
filterRoutes.push({ path: '*', redirect: '/404', hidden: true })
router.addRoutes(filterRoutes)
(2) 白屏
原因: 刷新后 vuex 中的数据消失, 会重新获取用户数据, 动态路由也会消失, 跳转的 next() 方法在动态路由重新添加之前已经放行, 所以需要重新指定路径
if (!store.state.user.userInfo.userId) {
// 表示之前获取过用户信息====不需要在重新获取了
const {
data: {
roles: { menus }
}
} = await store.dispatch('user/getInfo
// 添加动态路由但不显示到菜单中
// 筛选显示有权限的页面
const filterRoutes = asyncRoutes.filter((item) => {
return menus.includes(item.children[0].name)
})
filterRoutes.push({ path: '*', redirect: '/404', hidden: true })
router.addRoutes(filterRoutes)
// 存储routes到vuex
store.commit('user/setRoute', [...constantRoutes, ...filterRoutes])
next({
...to, // 证路由添加完了再进入页面 (可以理解为重进一次)
replace: true // 清除刷新的历史记录
})
} else {
next()
}
next跳转机制
next()
是放行,但是如果next()
里有参数的话,next()
就像被重载一样,就有了不同的功能。
在守卫中使用next('/login')
,肯定有人认为是会直接跳转到/login
路由:
beforeEach((to, from, next) => {
next('/login')
}
但是实际上是这样执行的:
beforeEach((to, from, next) => {
beforeEach(('/login', from, next) => {
beforeEach(('/login', from, next) => {
beforeEach(('/login', from, next) => {
beforeEac... // 一直循环下去...... , 因为我们没有使用 next() 放行
}
}
}
}
解决方案:
next('/login')不是说直接去/login路由,而是中断这一次路由守卫的操作,又进入一次路由守卫,就像嵌套一样,一层路由守卫,然后又是一层路由守卫,此时路由守卫进入到第二层时,to.path已经不是/login了,这个时候才执行next()放行操作。
// 判断这一次是否就是前往对应路由的beforeEach((to, from, next),如果是,就执行next()放行
if (to.path !== '/login') {
next({ path: '/login' })
} else {
next()
}
同时,该方法实际上走了两次路由判断,因此,需要将路由历史替换掉一个,防止点击后退按钮仍然是同一地址。
// replace: true告诉VUE本次操作后,不能通过浏览器后退按钮,返回前一个路由。
next({ ...to, replace: true })
- 最后,一句话来说,就是最终一定要执行一个没有参数的next()方法,使路由能够正常的跳转
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!