• vue3使用pinia 实现权限code存取



    前言

    上一篇 vue3+element-plus权限控制实现(el-tree父子级不关联情况处理)
    主要描述了权限控制综合实例中 el-tree 组件的使用细节。
    这一篇,主要讲讲pinia 来存取权限code ,并且在 router.beforeEach 实现菜单的权限控制。


    一、pinia 简要认识

    Pinia 起始于 2019 年 11 月左右的一次实验,其目的是设计一个拥有组合式 API 的 Vue 状态管理库。

    yarn add pinia
    # 或者使用 npm
    npm install pinia
    
    • 1
    • 2
    • 3
    import { createApp } from 'vue'
    import { createPinia } from 'pinia'
    import App from './App.vue'
    
    const pinia = createPinia()
    const app = createApp(App)
    
    app.use(pinia)
    app.mount('#app')
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    二、实现思路

    登录后获取用户的权限code,用pinia存储起来,在路由守卫 router.beforeEach 取到code 然后过滤路由菜单。我这里的路由表是提前写好在前端的,主要结构如下图,其中关键的是meta 里面自定义的code,根据这个来判断是否拥有权限的。

    
      {
        path: '/pathXXX',
        name: 'pathXXX',
        meta: {
          keepAlive: true, //设置页面是否需要使用缓存
          title: 'pathXXX',
          icon: 'ShoppingCart',
          code: 'PermissionCode'  // 权限code
        },
        component: Layout,
        redirect: '/pathXXX/list',
        children: [
          {
            name: 'subPathXXX',
            path: '/subPathXXX',
            component: () => import('@/views/subPathXXX/index.vue'),
            meta: {
              keepAlive: true, 
              title: 'subPathXXX',
              icon: 'ShoppingCart',
              menuCode: 'subPermissionCode'
            }
          }
        ]
      },
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    三、详细实现步骤

    1.用pinia 定义user store 用来存储用户相关的数据,安装 **js-cookie **来辅助存在cookie里

    import { defineStore } from 'pinia'
    import Cookie from 'js-cookie'
    import { getUserPermissonApi } from '@/api/xxx'
    /**
     * @description 获取cookie
     * @param name
     * @returns value
     */
    function getCookie(name: any) {
      return Cookie.get(name)
    }
    /**
     * @description 设置 cookie
     * @param name
     * @param value
     * @returns value
     */
    function setCookie(name: any, value: any) {
      return Cookie.set(name, value)
    }
    
    // 你可以对 `defineStore()` 的返回值进行任意命名,但最好使用 store 的名字,同时以 `use` 开头且以 `Store` 结尾。(比如 `useUserStore`,`useCartStore`,`useProductStore`)
    // 第一个参数是你的应用中 Store 的唯一 ID。
    export const useUserInfoStore = defineStore('app-user', {
      state: () => ({
        menuPermission: getCookie('key') ? JSON.parse(getCookie('key') as any) : {}
      }),
      actions: {
        setUserPermisson(info: any) {
          this.menuPermission = info
          setCookie('key', this.menuPermission ? JSON.stringify(this.menuPermission) : '[]')
        },
        async getUserPermisson(params: {}) {
          try {
            const { data } = await getUserPermissonApi(params)
            this.setUserPermisson(data) // 这里就是获取code 对应上文 路由表结构中meta.code 来判断是否显示该菜单
          } catch (erro) {
            console.warn(erro)
          }
        }
      }
    })
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43

    2. 在登录后获取用户的userId 与 token 后,调用定义好的 getUserPermisson 获取用户的权限code,并且存储起来

    <script setup>
    import { useUserInfoStore } from '@/store/modules/user'
    const store = useUserInfoStore ()
    const getUserPermissionCode = () => {
    	// 获取了用户userid 等
    	store.getUserPermisson({userid :xxx})
    }
    </script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    3. 在路由守卫 router.beforeEach 取到code 然后过滤路由菜单

    import { start, done, configure } from 'nprogress'
    // 提前写好路由表,主要meta.code 要对应上
    
    let asyncRoutes: RouteRecordRaws[] = [
      {
        path: '/Pathxx',
        name: 'Pathxx',
        meta: {
          keepAlive: true,
          title: 'Pathxx',
          icon: 'x',
          code: '/Pathxx'
        },
        component: Layout,
        redirect: '/Pathxx',
        children: [
          {
            name: 'subPathXX',
            path: '/subPathXX',
            component: () => import('@/views/subPathXX/index.vue'),
            meta: {
              keepAlive: true, 
              title: 'subPathXX',
              icon: 'subPathXX',
              menuCode: 'subPathXX'
            }
          }
        ]
      },
    ]
    
    configure({ showSpinner: false }) // NProgress 配置
    const whiteList = ['/login']
    router.beforeEach(async (to: RouteLocationNormalized, from: RouteLocationNormalized, next) => {
      start()
    
      const usePermission = usePermissionStore() //注意这个写在router.beforeEach 内部,写在外面有作用域问题
    
      const curToken = userStore.getToken
      if (curToken) {
        if (to.path === '/login') {
          next({ path: DefaultRoute })
          done()
        } else {
          try {
            const codeArr = usePermission.getMenuPermission || []
            const filterDynamicRoutes = (routes: any) => {
              for (let len = routes.length - 1; len >= 0; len--) {
                if (Array.isArray(codeArr) && codeArr.includes(routes[len].meta.menuCode)) {
                  // 说明都有
                  continue
                } else {
                  if (routes[len].children && routes[len].children.length > 0) {
                    filterDynamicRoutes(routes[len].children)
                  } else {
                    routes.splice(len, 1)
                  }
                }
              }
            }
            filterDynamicRoutes(asyncRoutes)
          
            next(to.path)
          } catch (error) {
            next(`${import.meta.env.VITE_BASE_REDIRECT_TO}?redirect=${to.path}`)
            done()
          }
        }
      } else {
        if (whiteList.includes(to.path)) {
          next()
        } else {
          done()
        }
      }
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76

    总结

    在本文我们一开始了解了pinia是什么以及如果安装使用。接着结合使用pinia实现菜单权限控制的综合实例,来进一步了解pinia的使用。

  • 相关阅读:
    写个续集,填坑来了!关于“Thread.sleep(0)这一行‘看似无用’的代码”里面留下的坑。
    oracle11g网络配置
    什么是前端脚手架?脚手架原理?
    VuePress实现自动获取文章侧边栏目录功能
    MyEclipse控制台console不停的自动跳动控制台界面,解决方案
    C标准库部分
    基于高德引擎的天地图切片加载
    用Python制作可视化GUI界面,一键实现多种风格的照片处理
    小程序InnerAudioContext设置问题记录
    【跨模态】【对比学习】CLIP:文本监督CV的预训练(2021)
  • 原文地址:https://blog.csdn.net/Bruce__taotao/article/details/133338491