权限应用 之 动态生成左侧菜单

目录

权限应用-动态生成左侧菜单-整体分析

分析

示例

 权限应用-动态生成左侧菜单-addRoutes方法

addRoutes基本使用

示例

在代码中书写

权限应用-动态生成左侧菜单-改写路由信息保存位置

分析

定义vuex管理菜单数据

1.补充模块,在src/store/modules下补充menu.js

2.提交setMenuList生成完整的菜单数据

3.菜单生成部分改写使用vuex中的数据

权限应用-使用权限数据做过滤处理

过滤的思路

从actions中返回菜单项

 在permission.js中获取action的返回值并过滤

小结

刷新页面时的bug修复

问题 

原因

解决

实现代码

 解决刷新出现的白屏bug

退出登录时重置路由

问题

原因

解决


上文说到,角色分配权限
,以及提到权限两个应用

动态生成左侧菜单 以及按钮级控制

权限应用-动态生成左侧菜单-整体分析

分析

登录成功(页面跳转),进入导航守卫:

  • 获取个人权限信息
  • 生成可以访问的动态路由

示例

 权限应用-动态生成左侧菜单-addRoutes方法

vue-router对象中的addRoutes,用它来动态添加路由配置

因为用户访问到的页面(路由配置)必须是动态的,所有要先掌握下可以动态添加路由地址的api

addRoutes基本使用

router.addRoutes([路由配置对象])
或者:
this.$router.addRoutes([路由配置对象])

示例

1.在views下创建页面

<template><h1>abc</h1></template>

2.通过代码添加路由配置

// 按钮
<button @click="hAddRoute">addRoute</button>

// 回调
hAddRoute() {
    this.$router.addRoutes([{
        path: '/abc',
        component: () => import('@/views/abc'),
        }])
},

点击了按钮之后,就可以在地址中访问/abc了

在代码中书写

1.在router/index.js中的路由配置中删除动态路由的部分

const createRouter = () => new Router({
  // mode: 'history', // require service support
  scrollBehavior: () => ({ y: 0 }),
  // routes: constantRoutes
  // 合并动态和静态的路由  , ...asyncRoutes
- routes: [...constantRoutes, ...asyncRoutes]
+ routes: [...constantRoutes]
})

2.在permission.js中引入,并使用addRoutes动态添加

把之前在router中直接静态写死的动态路由表改造成通过addRoutes 方法调用添加的形式

// 引入所有的动态路由表(未经过筛选)
+ import router, { asyncRoutes } from '@/router'

const whiteList = ['/login', '/404']
router.beforeEach(async(to, from, next) => {
  // 开启进度条
  NProgress.start()
  // 获取本地token 全局getter
  const token = store.getters.token
  if (token) {
    // 有token
    if (to.path === '/login') {
      next('/')
    } else {
      if (!store.getters.userId) {
        await store.dispatch('user/getUserInfo')
        // 改写成动态添加的方式
+       router.addRoutes(asyncRoutes)
      }
      next()
    }
  } else {
    // 没有token
    if (whiteList.includes(to.path)) {
      next()
    } else {
      next('/login')
    }
  }
  // 结束进度条
  NProgress.done()
})

效果

1.左侧的菜单只剩下静态的首页了

2.浏览器手动输入某一个动态路由地址,依旧是可用的,这证明了已经把动态路由添加到我们的路由系统了

权限应用-动态生成左侧菜单-改写路由信息保存位置

分析

当前的菜单渲染(src\layout\components\Sidebar\index.vue)使用的数据:this.$router.options.routes 这个数据是固定,我们通过addRoutes添加的路由表只存在内存中,并不会改变this.$router.options.routes

如果我们希望在调用addRoutes方法之后,要路由数据立刻反映到菜单中,我们需要想一个额外的方法,vue开发中,哪个技术可以保证响应式特性还可以动态修改? vuex

因此在vuex中保存菜单数据

定义vuex管理菜单数据

1.补充模块,在src/store/modules下补充menu.js

  • 定义数据menuList
  • 修改数据的方法setMenuList        
// 导入静态路由
import { constantRoutes } from '@/router'
export default {
  namespaced: true,
  state: {
    // 先以静态路由作为菜单数据的初始值
    menuList: [...constantRoutes]
  },
  mutations: {
    setMenuList(state, asyncRoutes) {
      // 将动态路由和静态路由组合起来
      state.menuList = [...constantRoutes, ...asyncRoutes]
    }
  }
}

当然,要在src/store/index.js中注册这个模块

+ import menu from './modules/menu'

Vue.use(Vuex)

const store = new Vuex.Store({
  modules: {
    app,
    settings,
    user,
+   menu
  },
  getters
})

2.提交setMenuList生成完整的菜单数据

修改src/permission.js中的代码

if (!store.getters.userId) {
        await store.dispatch('user/getUserInfo')

        // 动态添加可以访问的路由设置
        router.addRoutes(asyncRoutes)

        // 根据用户实际能访问几个页面来决定从整体8个路由设置
        // 中,过滤中出来几个,然后保存到vuex中
+       store.commit('menu/setMenuList', asyncRoutes)
      }

3.菜单生成部分改写使用vuex中的数据

在src\layout\components\Sidebar\index.vue文件中,修改

routes() {
  // 拿到的是一个完整的包含了静态路由和动态路由的数据结构
  // return this.$router.options.routes
  return this.$store.state.menu.menuList
}

权限应用-使用权限数据做过滤处理

上一步我们实现了

  • 把动态路由通过addRoutes动态添加到了路由系统里
  • 把动态路由保存到vuex的menu中

但是我们没有和权限数据做搭配,接下来我们通过接口返回的权限数据对动态菜单(8个页面)做过滤处理,以确定完成菜单与用户权限相关。

过滤的思路

过滤使用name作为标识,对照下标检查路由name是否一致

后端的接口约定如下:

  • 页面名字: 员工   标识: employees
  • 页面名字: 权限  标识: permissions
  • 页面名字: 组织架构  标识: departments
  • 页面名字: 设置 标识: settings
  • 页面名字: 工资  标识: salarys
  • 页面名字: 审核 标识: approvals
  • 页面名字: 考勤  标识: attendances
  • 页面名字: 社保 标识: social_securitys

从actions中返回菜单项

用户能访问哪些页面是通过actions获取到的,只需要从action中返回即可。

修改 store/modules/user.js ,补充return语句。

// 用来获取用户信息的action
    async getUserInfo(context) {
      // 1. ajax获取基本信息,包含用户id
      const rs = await getUserInfoApi()
      console.log('用来获取用户信息的,', rs)
      // 2. 根据用户id(rs.data.userId)再发请求,获取详情(包含头像)
      const info = await getUserDetailById(rs.data.userId)
      console.log('获取详情', info.data)
      // 把上边获取的两份合并在一起,保存到vuex中
      context.commit('setUserInfo', { ...info.data, ...rs.data })
      // 当前用户可以看到的菜单 res.data.roles.menus
+     return rs.data.roles.menus
    },

 在permission.js中获取action的返回值并过滤

src/permission.js

if (!store.getters.userId) {
        // 有token,要去的不是login,就直接放行
        // 进一步获取用户信息
        // 发ajax---派发action来做
+       const menus = await store.dispatch('user/getUserInfo')
        console.log('当前用户能访问的页面', menus) // ['salarys', 'settings']
        console.log('当前系统功能中提供的所有的动态路由页面是', asyncRoutes)
        // 根据本用户实际的权限menus去 asyncRoutes 中做过滤,选出本用户能访问的页面

+       const filterRoutes = asyncRoutes.filter(route => {
+         const routeName = route.children[0].name
+         return menus.includes(routeName)
+       })

        // 一定要在进入主页之前去获取用户信息

        // addRoutes用来动态添加路由配置
        // 只有在这里设置了补充了路由配置,才可能去访问页面
        // 它们不会出现左侧
+       router.addRoutes(filterRoutes)

        // 把它们保存在vuex中,在src\layout\components\Sidebar\index.vue
        // 生成左侧菜单时,也应该去vuex中拿
+       store.commit('menu/setMenuList', filterRoutes)
      }

小结

  • 语法: 从actions中获取返回值
  • asyncRoutes.filter

刷新页面时的bug修复

问题 

(1)如果我们刷新浏览器,会发现跳到了404页面

(2)对于addRoute添加的路由,在刷新时会白屏

原因

刷新浏览器,会发现跳到了404页面

现在我们的路由设置中的404页处在中间位置而不是所有路由的末尾了。

解决

把404页改到路由配置的最末尾就可以了

实现代码

1.从route/index.js中的静态路由中删除path:'*'这一项

// 不需要特殊的权限控制就可以访问的页面
export const constantRoutes = [
  {
    path: '/login',
    component: () => import('@/views/login/index'),
    hidden: true
  },
  
  // 404 page must be placed at the end !!!
-  { path: '*', redirect: '/404', hidden: true }
]

2.在permission.js中补充在最后

// if(没有userInfo) {
if (!store.getters.userId) {
  // 有token,要去的不是login,就直接放行
  // 进一步获取用户信息
  // 发ajax---派发action来做
  const menus = await store.dispatch('user/getUserInfo')
  console.log('当前用户能访问的页面', menus)
  console.log('当前系统功能中提供的所有的动态路由页面是', asyncRoutes)
  // 根据本用户实际的权限menus去 asyncRoutes 中做过滤,选出本用户能访问的页面

  const filterRoutes = asyncRoutes.filter(route => {
    const routeName = route.children[0].name
    return menus.includes(routeName)
  })

  // 一定要在进入主页之前去获取用户信息

  // 把404加到最后一条
+  filterRoutes.push( // 404 page must be placed at the end !!!
    { path: '*', redirect: '/404', hidden: true })

  // addRoutes用来动态添加路由配置
  // 只有在这里设置了补充了路由配置,才可能去访问页面
  // 它们不会出现左侧
  router.addRoutes(filterRoutes)

  // 把它们保存在vuex中,在src\layout\components\Sidebar\index.vue
  // 生成左侧菜单时,也应该去vuex中拿
  store.commit('menu/setMenuList', filterRoutes)
}

 解决刷新出现的白屏bug

if (!store.getters.userId) {
  // 省略其他...
  // 解决刷新出现的白屏bug
  next({
    ...to, // next({ ...to })的目的,是保证路由添加完了再进入页面 (可以理解为重进一次)
    replace: true // 重进一次, 不保留重复历史
  })
} else {
  next()
}

退出登录时重置路由

问题

退出后,再次登陆,发现菜单异常 (控制台有输出说路由重复);

原因

路由设置是通过router.addRoutes(filterRoutes)来添加的,退出时,并没有清空,再次登陆,又加了一次,所以有重复。

需要将路由权限重置 (恢复默认)   将来登录后再次追加才可以,不然的话,就会重复添加

解决

我们的router/index.js文件,发现一个重置路由方法

// 重置路由
export function resetRouter() {
  const newRouter = createRouter()
  router.matcher = newRouter.matcher // 重新设置路由的可匹配路径
}
 

这个方法就是将路由重新实例化,相当于换了一个新的路由,之前加的路由就不存在了,需要在登出的时候, 调用一下即可

store/modules/user.js

import { resetRouter } from '@/router'
// 退出的action操作
logout(context) {
  // 1. 移除vuex个人信息
  context.commit('removeUserInfo')
  // 2. 移除token信息
  context.commit('removeToken')
  // 3. 重置路由
  resetRouter()
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值