Vue 动态权限路由实现菜单列表之进阶版

需求:根据登录用户的权限,显示不同导航菜单也,同时操作不同的界面。

(1)首先在本地配置好固定不变的路由地址,例如登录,首页这些页面,如下:

import Vue from 'vue'
import Router from 'vue-router'
import LoginView from '@/views/login/Common'

Vue.use(Router)

let constRouter = [
  { path: '/login', name: '登录页', component: LoginView },
  { path: '/index', name: '首页', redirect: '/home' }
]

let router = new Router({
  routes: constRouter
})

export default router

(2)全局前置守卫:router.beforeEach,渲染动态路由。

当一个导航触发时,全局前置守卫按照创建顺序调用。守卫是异步解析执行,此时导航在所有守卫 resolve 完之前一直处于 等待中

每个守卫方法接收三个参数:

  • to: Route: 即将要进入的目标 路由对象

  • from: Route: 当前导航正要离开的路由

  • next: Function: 一定要调用该方法来 resolve 这个钩子。执行效果依赖 next 方法的调用参数。

const whiteList = ['/login']
let asyncRouter

router.beforeEach((to, from, next) => {
  if (whiteList.indexOf(to.path) !== -1) {
    next()
  }
  let token = db.get('USER_TOKEN')
  let user = db.get('USER')
  let userRouter = get('USER_ROUTER')  // 获取本地缓存
  if (token.length && user) {
    if (!asyncRouter) {
      if (!userRouter) {
        // 请求用户菜单列表接口
      } else {
        asyncRouter = userRouter
      }
    } else {
      next()
    }
  } else {
    next('/login')
  }
})

主要逻辑分为下面几步:

  1. 判断要跳转的路由地址是否在路由白名单内,是的话放行,不是的话进行第2步;

  2. 从内存中获取token和用户信息,如果存在则进行第3步,不存在跳转到登录页;

  3. 判断动态路由信息是否存在,存在则放行,不存在则进行第4步;

  4. 判断用户路由是否已经加载,是的话将用户路由赋值给动态路由,并执行路由添加操作,然后跳转;如果用户路由不存在,则执行第5步;

  5. 根据用户名从后台获取用户路由信息,并将其保存到内存中,再执行路由添加操作,然后跳转

(3)通过接口返回的权限菜单列表信息;

request.get(`menu/${user.username}`).then((res) => {
  asyncRouter = res.data
  save('USER_ROUTER', asyncRouter)  // 本地缓存
  go(to, next)
})

接口返回的路由信息:

(4)拿到权限路由信息后,需要我们在本地对数据进行处理,注册动态路由:router.addRoutes 是动态添加更多的路由规则。参数必须是一个符合 routes 选项要求的数组。

function go (to, next) {
  asyncRouter = filterAsyncRouter(asyncRouter)
  router.addRoutes(asyncRouter)
  next({...to, replace: true})
}

(5)通过 filterAsyncRouter 方法,将传入的路由数组中 component 属性做处理之后,返回数组。

import Vue from 'vue'
import Router from 'vue-router'
import MenuView from '@/views/common/MenuView'
import PageView from '@/views/common/PageView'
import EmptyPageView from '@/views/common/EmptyPageView'
import HomePageView from '@/views/HomePage'

function filterAsyncRouter (routes) {
  return routes.filter((route) => {
    let component = route.component
    if (component) {
      switch (route.component) {
        case 'MenuView': route.component = MenuView  break
        case 'PageView': route.component = PageView  break
        case 'EmptyPageView': route.component = EmptyPageView break
        case 'HomePageView': route.component = HomePageView  break
        default: route.component = view(component)
      }
      if (route.children && route.children.length) {
        route.children = filterAsyncRouter(route.children)
      }
      return true
    }
  })
}

(6)根据路由,导入对应真实的文件信息:

function view (path) {
  return function (resolve) {
    import(`@/views/${path}.vue`).then(mod => {
      resolve(mod)
    })
  }
}

(7)如何正确显示左边菜单栏信息呢?

// 底层组件
render (h) {
  return h(
    Menu,
    {
      props: {
        theme: this.$props.theme,
        mode: this.$props.mode,
        openKeys: this.openKeys,
        selectedKeys: this.selectedKeys
      },
      on: {
        openChange: this.onOpenChange,
        select: (obj) => {
          this.selectedKeys = obj.selectedKeys
          this.$emit('select', obj)
        }
      }
    }, this.renderMenu(h, this.menuData)
  )
}

(8)父组件调用菜单组件:

// GlobalLayout.vue
<sider-menu :theme="theme" :menuData="menuData" :collapsed="false" :collapsible="false" @menuSelect="onMenuSelect"/>

let menuData = []
beforeCreate () {
  let routers = this.$db.get('USER_ROUTER')
  menuData = routers.find((item) => item.path === '/').children.filter((menu) => {
    let meta = menu.meta
    if (typeof meta.isShow === 'undefined') {
      return true
    } else return meta.isShow
  })
}
// SiderMenu.vue
<i-menu :theme="theme" :collapsed="collapsed" :menuData="menuData" @select="onSelect"/>
wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==uploading.4e448015.gif转存失败重新上传取消 wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值