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()方法,使路由能够正常的跳转
posted @   嗤嗤13  阅读(83)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!
点击右上角即可分享
微信分享提示