vue权限管理(动态路由)

技术栈:vue2.x + vuex +element-ui + vue-router2.x 使用vue-router的addRoutes,优化公司后台项目的权限管理

🧐 权限管理(动态路由)

复制代码
## 现状:
-router.js 所有路由
-resource.js 资源码文件
步骤:

路由拦截器中根据是否存在token来请求接口,获取用户所有资源码,若无token,返回到登录页
获取到资源码后,使用vuex储存有权限的路由并生成 menu菜单导航

缺点:
只是单纯控制了菜单,没有对路由进行权限控制
解决方案:
使用vue-router的 addRouters 对路由进行动态添加,
步骤: 

路由

在路由中添加字段 btnCodes 表示 该页面下的权限按钮的内容 code表示路由权限码

javascript 复制代码
btncodes:{code:'',name:''}

路由守卫

使用`vuex`对获取到资源码进行处理,获取到最新的addRouters 然后添加到路由中

在使用动态添加路由addRoutes()会遇到下面的情况:

在addRoutes()之后第一次访问被添加的路由会白屏,这是因为刚刚addRoutes()就立刻访问被添加的路由,然而此时addRoutes()没有执行结束,因而找不到刚刚被添加的路由导致白屏。因此需要从新访问一次路由才行。

该如何解决这个问题 ? 此时就要使用next({ ...to, replace: true })来确保addRoutes()时动态添加的路由已经被完全加载上去。

next({ ...to, replace: true })中的replace: true只是一个设置信息,告诉VUE本次操作后,不能通过浏览器后退按钮,返回前一个路由。

因此next({ ...to, replace: true })可以写成next({ ...to }),不过你应该不希望用户在addRoutes()还没有完成的时候,可以点击浏览器回退按钮.

javascript 复制代码
import store from '../store/index'
import { getResources} from '@/api'
import { Message } from 'ELEMENT'
import { errorRouter, homeRouter } from './routes'

// 路由守卫
export default function guards(router) {
  router.beforeEach(async (to, from, next) => {
    const token = localStorage.getItem('token')
    console.log(to)
    if (to.path === '/user/login') {
      next()
    } else {
      if (token) {
        if (store.state.permission.registerRouteFresh) {
            const result =await getResources()
              
              if (result.code === 200) {
                const resources = result.data || []
                store.dispatch('GenerateRoutes', resources).then(() => {
                  const currentAddRouter = [{...homeRouter,children:[...store.getters.addRouters]},{...errorRouter}]
                  router.addRoutes([...currentAddRouter])
                  store.commit('SET_REGISTER_ROUTE_FRESH', false)
                  next({ ...to, replace: true })
                })
              } else {
                Message.error('菜单数据获取失败, 请刷新页面')
              }
          
        }
        next()
      } else {
        next('/user/login')
      }
    }
    // 兜底执行
    next()
  })
}

store

使用vuex 对路由权限 和权限码进行存储

复制代码
import {asyncRouterMap, constantRouterMap } from '@/pages/mall/router/routes'
import { deepCopy,getPermissionRouter } from '@/utils'

function contrast(a, b) {
  if (a.code == b.code && a.path && !a.isProhibit) {
    a.display = true
  }
  if (a.children && a.children.length > 0) {
    a.children.forEach(item => {
      contrast(item, b)
    })
  }
}

function setFlagRouter(routerMap, resources) {
  resources.forEach(res => {
    routerMap.forEach(route => {
      contrast(route, res)
    })
  })
}

function filterRouter(routers) {
  if (!routers.length) {
    return
  }

  let i = routers.length
  while (i--) {
    if (!routers[i].display) {
      continue
    }

    if (routers[i].children && routers[i].children.length > 0) {
      if (!routers[i].hasChildren) {
        continue
      }
      let arr = routers[i].children
      let flag = true
      for (let k = 0; k < arr.length; k++) {
        if (arr[k].display) {
          flag = false
          break
        }
      }
      if (flag) {
        routers[i].display = false
      } else {
        filterRouter(routers[i].children)
      }
    }
  }
}

const permission = {
  state: {
    routers: constantRouterMap,
    resources: [],
    registerRouteFresh: true,
    addRouters: null
  },
  mutations: {
    SET_REGISTER_ROUTE_FRESH: (state, flag) => {
      state.registerRouteFresh = flag
    },
    SET_RESOURCES: (state, resources) => {
      state.resources = resources
    },
    SET_ROUTERS: (state, routers) => {
      state.addRouters = routers
      state.routers = constantRouterMap.concat(routers)
    },
  },
  actions: {
    GenerateRoutes({ commit }, data) {
      return new Promise(resolve => {
        let routerMap = deepCopy(asyncRouterMap )
        if (data.length) {
          setFlagRouter(routerMap, data)
          filterRouter(routerMap)
        }
        const accessedRouters = getPermissionRouter(routerMap, data)
        commit('SET_RESOURCES', data)
        commit('SET_ROUTERS', accessedRouters)
        resolve()
      })
    }
  }
}

export default permission

按钮权限

自定义指令v-permission

javascript 复制代码
import store from '../store'

const permissionDirective = {
  componentUpdated: function (el, binding, vnode) {
    let timer = null
    timer = setInterval(() => {
      if (!store.state.permission.registerRouteFresh) {
        const { value } = binding
        // 获取没有权限资源码列表数据
        const points = store.state.permission.resources
        if (value && value instanceof Array) {
          console.log(value);
          
          匹配对应的指令
          const hasPermission = points.some((point) => {
            return value.includes(point)
          })
          // 如果匹配, 则表示当前用户无该权限, 那么删除对应的功能按钮
          if (!hasPermission) {
            el.parentNode && el.parentNode.removeChild(el)
          }
        } else {
          throw new Error('v-premission Error')
        }
        clearInterval(timer)
      }
    }, 100)
  },
  unbind: function (el, binding) {}
}

export function setPermissionDirective(app) {
  app.directive('permission', permissionDirective)
}

export default permissionDirective
相关推荐
zyk_52011 分钟前
前端渲染pdf文件解决方案-pdf.js
前端·javascript·pdf
Apifox.18 分钟前
Apifox 4月更新|Apifox在线文档支持LLMs.txt、评论支持使用@提及成员、支持为团队配置「IP 允许访问名单」
前端·人工智能·后端·ai·ai编程
划水不带桨25 分钟前
大数据去重
前端
沉迷...30 分钟前
手动实现legend 与 echarts图交互 通过js事件实现图标某项的高亮 显示与隐藏
前端·javascript·echarts
可观测性用观测云1 小时前
观测云数据在Grafana展示的最佳实践
前端
uwvwko1 小时前
ctfhow——web入门214~218(时间盲注开始)
前端·数据库·mysql·ctf
Json____1 小时前
使用vue2开发一个医疗预约挂号平台-前端静态网站项目练习
前端·vue2·网站模板·静态网站·项目练习·挂号系统
HuaHua的世界1 小时前
说说 Vue 中 CSS scoped 的原理?
css·vue.js
littleplayer1 小时前
iOS Swift Redux 架构详解
前端·设计模式·架构
工呈士1 小时前
HTML 模板技术与服务端渲染
前端·html