vue + addRouters 实现动态路由菜单

动态路由这个功能呢,其实说简单也简单,说难也有点难度。
上代码
login组件

//template和style略过
<script>
import router from '@/router'  //引入路由
import Layout from '@/layout'  //引入框架组件1
import Block from '@/layout/block'   //引入框架组件2,框架组件的数量看各自项目实际来
const _import = require('@/router/import')  //module.exports = file => () => import(`@/${file}/index.vue`) 就这一行代码。作用是将字符串转换为懒加载路由组件

export default {
  data() {
   return {   //定义需要用到的变量
      roleId: '',
      menuList: [],
      menu: [],
      topMenus: [],
      leftMenus: [],
      firstUrl: ''
    }
  },
  created() {  //登录页面和404页面不属于动态路由页面,在创建页面前应添加到路由列表中
    router.options.routes = [
      {
        path: '/view/manager/login',
        component: () => import('@/view/manager/login')
      },
      {
        path: '/view/manager/404',
        component: () => import('@/view/manager/404'),
        hidden: true
      }
    ]
  },
  methods: {
    async getRole() {  //登录完成后获取到不同角色的Id,通过此Id获取对应的不同路由列表
      try {
        const res = await auth.privilege({
          method: 'get',
          roleId: this.roleId
        })
        console.log('role', res)
        //接下来就是漫长的数据格式转换了,这里根据各自的实际情况来
        if (res.status === 0) {
          const _res = res.result.menus
          const permissions = res.result.permissions
          const o = this.menuList
          this.firstUrl = _res[0].menuUrl
          for (var i = 0; i < _res.length; i++) {
            var index = _res[i]
            o[i] = {}
            o[i].path = index.menuUrl
            o[i].meta = {}
            o[i].meta.title = index.menuName
            o[i].meta.icon = index.menuIcon
            o[i].parentMenuId = index.parentMenuId
            o[i].menuId = index.menuId
            o[i].moduleId = index.moduleId
            if (index.menuLevel === 1) {
              o[i].component = 'Layout'
              o[i].redirect = ''
              o[i].children = []
            } else if (index.menuLevel === 2) {
              o[i].component = 'Block'
              o[i].redirect = ''
              o[i].children = []
            } else if (index.menuLevel === 3) {
              o[i].component = index.menuUrl
            } else if (index.menuLevel === 4) {
              o[i].component = index.menuUrl
              o[i].hidden = true
            }
            if (index.moduleId === 1010 && index.parentMenuId === 0) {
              o[i].hidden = true
            } else if (index.moduleId === 1013 && index.parentMenuId === 0) {
              o[i].hidden = true
            }
          }
          for (var j = 0; j < o.length; j++) {
            var pindex = o[j]
            for (var k = 0; k < o.length; k++) {
              var cindex = o[k]
              if (cindex.parentMenuId === pindex.menuId) {
                pindex.children.push(cindex)
                pindex.redirect = pindex.children[0].path
              }
            }
          }
          o.forEach(item => {
            if (item.parentMenuId === 0) {
              this.menu.push(item)
            }
            if (item.parentMenuId === 0 && item.moduleId === 1010) {
              this.topMenus.push(item)
            }
            if (item.parentMenuId === 0 && item.moduleId === 1013) {
              this.topMenus.push(item)
            }
          })
          //为了防止刷新后页面空白,需要将处理好的路由存储在sessionStorage中
          sessionStorage.setItem('permissions', JSON.stringify(permissions))
          sessionStorage.setItem('routerMenus', JSON.stringify(this.menu))
          sessionStorage.setItem('routerTopMenus', JSON.stringify(this.topMenus))
          var routes = filterAsyncRouter(this.menu)
          routes.push({
            path: '*',
            redirect: '/view/manager/404',
            hidden: true
          })
          // 添加权限路由
          routes.forEach(item => {
            router.options.routes.push(item)
          })
          // 加这一步才能渲染页面,不然页面显示为空白
          router.addRoutes(routes)
          //将路由同步存储到vuex中
          this.$store.dispatch('user/getPermissions', permissions)
          this.$store.dispatch('user/getMenus', routes)
          this.$store.dispatch('user/getTopMenus', this.topMenus)
          this.$router.push(this.firstUrl)
        } else {
          this.$message({
            message: res.msg,
            type: 'warning'
          })
        }
      } catch (err) {
        console.log(err)
        this.buttonLoading = false
        this.$message({
          message: err.data.msg ? err.data.msg : '网络错误',
          type: 'warning'
        })
      }
    }
  }
}
//这是对框架组件进行特殊处理的函数
function filterAsyncRouter(asyncRouterMap) {
  const accessedRouters = asyncRouterMap.filter(route => {
    if (route.component) {
      if (route.component === 'Layout') { // Layout组件特殊处理
        route.component = Layout
      } else if (route.component === 'Block') { // Block组件特殊处理
        route.component = Block
      } else {
        route.component = _import(route.path.substring(1, route.path.length))
      }
    }
    if (route.children && route.children.length) {
      route.children = filterAsyncRouter(route.children)
    }
    return true
  })
  return accessedRouters
}

</script>

为了防止页面刷新后空白,还有一步操作:
App.vue

//template和style同样略过
<script>
import Layout from '@/layout'
import Block from '@/layout/block'
import router from './router'
const _import = require('@/router/import')

export default {
//将路由信息从sessionStorage中取出来
  created() {
    const userInfo = JSON.parse(sessionStorage.getItem('userInfo'))
    const routerMenus = JSON.parse(sessionStorage.getItem('routerMenus'))
    const routerTopMenus = JSON.parse(sessionStorage.getItem('routerTopMenus'))
    const permissions = JSON.parse(sessionStorage.getItem('permissions'))
    if (routerMenus && this.$store.state.user.menus.length === 0) {
      this.$store.dispatch('user/getUserInfo', userInfo)
      this.$store.dispatch('user/getMenus', routerMenus)
      this.$store.dispatch('user/getTopMenus', routerTopMenus)
      this.$store.dispatch('user/getPermissions', permissions)
      var routes = filterAsyncRouter(routerMenus)
      routes.push({
        path: '*',
        redirect: '/view/manager/404',
        hidden: true
      })
      // 下面的操作同理
      // 添加权限路由
      routes.forEach(item => {
        router.options.routes.push(item)
      })
      // 加这一步才能渲染页面
      router.addRoutes(routes)
    }
  }

}

function filterAsyncRouter(asyncRouterMap) {
  const accessedRouters = asyncRouterMap.filter(route => {
    if (route.component) {
      if (route.component === 'Layout') {
        route.component = Layout
      } else if (route.component === 'Block') {
        route.component = Block
      } else {
        route.component = _import(route.path.substring(1, route.path.length))
      }
    }
    if (route.children && route.children.length) {
      route.children = filterAsyncRouter(route.children)
    }
    return true
  })
  return accessedRouters
}
</script>

至此,大功告成。
处理路由格式那一块跟业务有很强的关联性,但逻辑大同小异:
1,如果后端直接返回处理好的路由列表,那皆大欢喜,直接用即可。
2,如果后端返回给前端的是各路由之间的关系,那就需要前端自己去转换为所需的路由列表。但是前端只要弄清楚了每层路由间的联系,处理起来就不会很难。
3,前端必知的各路由关系数据

  1. 每一级路由的id
  2. 每一级路由的name
  3. 每一级路由的path
  4. 每一级路由所属的level
  5. 每一级路由的icon
  6. 每一级路由的id对应的所属父级的id
  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值