动态路由,动态侧边栏菜单

动态加载侧栏菜单

数据案例:后台返回的 json数据,请点击跳到文章最后查看

有三种方法可实现,但都有各自的缺点

  • 第一种(不推荐)
    注册所有的路由,根据动态菜单动态加载
    缺点:不安全,用户可以通过更改浏览的的路径进去他没有权限的页面
  • 第二种(不推荐)
    通过枚举定义每个角色的路由,根据角色为其注册
    缺点:不够灵活,如果某个角色需要添加一个新的路由权限,就需要手动改前端代码重新发布
  • 第三种(推荐)
    通过后台返回的菜单去动态注册路由,需要添加路由时就让后端去修改好了,后台返回什么就注册什么(不关我事哈;后台的锅是😄)

这里使用第三种方法

主要分两步:

  1. 动态注册路由
  2. 将渲染动态菜单

目的:往路由/main里动态添加子路由
router/index.ts

const routes: Array<RouteRecordRaw> = [
  {
    path: '/',
    redirect: '/main'
  },
  {
    path: '/login',
    name: 'login',
    component: () => import('@/views/login/index.vue')
  },
  {
    path: '/main',
    name: 'main',
    component: () => import('@/views/main/main.vue')
    // children: [] 往这里面添加子路由
  },
  {
    path: '/:pathMatch(.*)*',
    name: 'not-found',
    component: () => import('@/views/not-found/404.vue')
  }
]

第一步:动态加载路由

注意:实际开发中,各级目录的获取实际看后台返回的数据,不管返回的数据是什么,目的都是为了拿到一二…级目录为其注册路由

通过观察返回数据可知,数据中 type=1 为一级目录,type=2为二级目录,type=3为权限

根据返回的数据先创建,对应的vue文件路由

路由:以overview为例 overview.ts

const overview = () => import('@/views/main/analysis/overview/overview.vue')
export default {
  path: '/main/analysis/overview',
  name: 'overview',
  component: overview,
  children: []
}

vue文件:overview.vue

<template>
  <div>overview</div>
</template>

<script lang="ts">
import { defineComponent } from 'vue'

export default defineComponent({
  setup() {
    return {}
  }
})
</script>

<style scoped></style>

根据案例的数据,这里写一个递归函数对一二级目录的抽取
新建 `utils/map-menu.ts’
思路:

  1. 先加载默认所有的routers
  2. 根据菜单获取需要的routers动态加载(递归查找符合条件的路由并添加到routes里等待添加到router.main.children
  3. 将路由注册,即将routes 添加到 router.main.children
import { RouteRecordRaw } from 'vue-router'
import router from '@/router'
export function mapMenuToRoutes(userMenu: any[]): RouteRecordRaw[] {
  const routes: RouteRecordRaw[] = []

  //1.先加载默认所有的routers
  const allRouters: RouteRecordRaw[] = []
  // webpack提供的require.context,可获取文件夹下的所有文件
  // require.context(需获取文件所在的文件夹,是否递归查找,获取规则【正则表达式】)
  const routerFiles = require.context('../router/main', true, /\.ts/)
  // console.log('routerFiles', routerFiles.keys())
  routerFiles.keys().forEach((key) => {
    const route = require('../router/main' + key.split('.')[1])
    const routeArr = route.default
    // console.log(route.default)
    allRouters.push(routeArr)
  })
  // 2.根据菜单获取需要的routers动态加载

  //递归查找符合条件的路由并添加到routes里等待加载
  const _recurseGetRoute = (menus: any) => {
    for (const menu of menus) {
      if (menu.type === 2) {
        const needRoute = allRouters.find((item) => {
          return item.path == menu.url
        })
        if (needRoute) {
          routes.push(needRoute)
        }
        if (!firstMenu) {
          firstMenu = needRoute
        }
      } else {
        _recurseGetRoute(menu.children)
      }
    }
  }
  _recurseGetRoute(userMenu)

  // console.log('routes', routes)
  //将路由注册,即将routes 添加到 router.main.children
  routes.forEach((element) => {
    router.addRoute('main', element)
  })

  return routes
}

第二步:渲染动态菜单

  1. 通过上面获取到的全部 json数据(即后台返回的原数据)通过el-menu组件渲染
  2. 为每个菜单添加路由

在· utils/map-menu.ts 添加用于获取当期路由的递归函数

let currentMenu: any = null
export function pathMapToMenu(userMenu: any[], currentPath: string): any {
  // console.log(userMenu)

  for (const item of userMenu) {
    if (item.type === 2 && item.url === currentPath) {
      //找到了当前路径对应的路由
      // console.log(item)
      if (!currentMenu) {
        currentMenu = item
      }
      return item
    } else {
      pathMapToMenu(item.children ?? [], currentPath)
    }
  }
}
export {currentMenu}

在侧边栏组件添加动态菜单,并调用上面的函数,为每个菜单添加路由

<template>
  <div>
    <div class="logo">
      <img class="img" src="@/assets/logo透明.png" />
      <div v-if="!collapse" class="title">后台管理端</div>
    </div>

    <div>
      <el-menu
        active-text-color="#ffd04b"
        background-color="#0a2137"
        class="el-menu-vertical-demo"
        :collapse-transition="false"
        :default-active="defaultValue"
        :unique-opened="true"
        :collapse="collapse"
        text-color="#fff"
      >
        <template v-for="item in userMenus" :key="item.id + ''">
          <!-- 二级菜单 -->
          <template v-if="item.type === 1">
            <el-sub-menu :index="item.id + ''">
              <template #title>
                <el-icon v-if="item.icon"
                  ><component :is="getIcon(item.icon)"
                /></el-icon>
                <span>{{ item.name }}</span>
              </template>

              <el-menu-item-group>
                <template
                  v-for="subItem in item.children"
                  :key="subItem.id + ''"
                >
                  <el-menu-item
                    :index="subItem.id + ''"
                    @click="clickMenuItem(subItem)"
                  >
                    <el-icon v-if="subItem.icon"
                      ><component :is="getIcon(subItem.icon)"
                    /></el-icon>
                    <span>{{ subItem.name }}</span>
                  </el-menu-item>
                </template>
              </el-menu-item-group>
            </el-sub-menu>
          </template>
          <!-- 一级菜单 -->
          <template v-else-if="item.type === 2">
            <el-menu-item :index="item.id + ''" @click="clickMenuItem(item)">
              <el-icon v-if="item.icon"
                ><component :is="getIcon(item.icon)"
              /></el-icon>
              <span>{{ item.name }}</span>
            </el-menu-item>
          </template>
        </template>
      </el-menu>
    </div>
  </div>
</template>
<script lang="ts">
import { defineComponent, computed, ref } from 'vue'
import { userStore } from '@/store'
import { IMenuItemState } from './type'
import { useRouter, useRoute } from 'vue-router'
import { pathMapToMenu, currentMenu } from '@/utils/map-menu'
export default defineComponent({
  props: {
    collapse: {
      type: Boolean,
      default: false
    }
  },
  setup() {
    const store = userStore()
    const router = useRouter()
    const route = useRoute()
    const currentPath = route.path

    console.log('currentPath', currentPath)
    const userMenus = store.state.login.userMenus
    // console.log(userMenus)

    pathMapToMenu(userMenus, currentPath)
    const defaultValue = ref(currentMenu.id + '')
    // console.log('currentPathMenu', currentMenu)

    const getIcon = (icon: string): string => {
      const iconArr = icon.split('-')
      if (iconArr.length > 3) {
        iconArr.splice(0, 2)
        return iconArr.join('-')
      } else {
        return iconArr[2]
      }
    }
    const clickMenuItem = (menuItem: any) => {
      router.push({
        path: menuItem.url ?? 'not-found'
      })
    }

    return {
      userMenus,
      getIcon,
      clickMenuItem,
      defaultValue
    }
  }
})
</script>
<style scoped lang="less">
.logo {
  display: flex;
  flex-wrap: nowrap;
  height: 48px;
  overflow: hidden;
  .img {
    // height: 40px;
    width: 40px;
    height: auto;
    padding: 4px 10px;
  }
  .title {
    line-height: 44px;
    color: #fff;
    font-size: 18px;
  }
}
.el-menu-item.is-active {
  background-color: #434a50 !important;
}
.el-menu-item {
  // background-color: #545c64;
}
/deep/ .el-menu-item-group__title {
  padding: 0;
}
.el-menu-vertical-demo:not(.el-menu--collapse) {
  width: 210px;
  // transition: 1s linear all !important;
  // min-height: 400px;
}
.el-menu {
  border-right: none;
}
</style>

到这里动态侧边栏菜单就完成了

json数据

[
    {
        "id": 38,
        "name": "系统总览",
        "type": 1,
        "url": "/main/analysis",
        "icon": "el-icon-monitor",
        "sort": 1,
        "children": [
            {
                "id": 39,
                "url": "/main/analysis/overview",
                "name": "核心技术",
                "sort": 106,
                "type": 2,
                "children": null,
                "parentId": 38
            },
            {
                "id": 40,
                "url": "/main/analysis/dashboard",
                "name": "商品统计",
                "sort": 107,
                "type": 2,
                "children": null,
                "parentId": 38
            }
        ]
    },
    {
        "id": 1,
        "name": "系统管理",
        "type": 1,
        "url": "/main/system",
        "icon": "el-icon-setting",
        "sort": 2,
        "children": [
            {
                "id": 2,
                "url": "/main/system/user",
                "name": "用户管理",
                "sort": 100,
                "type": 2,
                "children": [
                    {
                        "id": 5,
                        "url": null,
                        "name": "创建用户",
                        "sort": null,
                        "type": 3,
                        "parentId": 2,
                        "permission": "system:users:create"
                    },
                    {
                        "id": 6,
                        "url": null,
                        "name": "删除用户",
                        "sort": null,
                        "type": 3,
                        "parentId": 2,
                        "permission": "system:users:delete"
                    },
                    {
                        "id": 7,
                        "url": null,
                        "name": "修改用户",
                        "sort": null,
                        "type": 3,
                        "parentId": 2,
                        "permission": "system:users:update"
                    },
                    {
                        "id": 8,
                        "url": null,
                        "name": "查询用户",
                        "sort": null,
                        "type": 3,
                        "parentId": 2,
                        "permission": "system:users:query"
                    }
                ],
                "parentId": 1
            },
            {
                "id": 3,
                "url": "/main/system/department",
                "name": "部门管理",
                "sort": 101,
                "type": 2,
                "children": [
                    {
                        "id": 17,
                        "url": null,
                        "name": "创建部门",
                        "sort": null,
                        "type": 3,
                        "parentId": 3,
                        "permission": "system:department:create"
                    },
                    {
                        "id": 18,
                        "url": null,
                        "name": "删除部门",
                        "sort": null,
                        "type": 3,
                        "parentId": 3,
                        "permission": "system:department:delete"
                    },
                    {
                        "id": 19,
                        "url": null,
                        "name": "修改部门",
                        "sort": null,
                        "type": 3,
                        "parentId": 3,
                        "permission": "system:department:update"
                    },
                    {
                        "id": 20,
                        "url": null,
                        "name": "查询部门",
                        "sort": null,
                        "type": 3,
                        "parentId": 3,
                        "permission": "system:department:query"
                    }
                ],
                "parentId": 1
            },
            {
                "id": 4,
                "url": "/main/system/menu",
                "name": "菜单管理",
                "sort": 103,
                "type": 2,
                "children": [
                    {
                        "id": 21,
                        "url": null,
                        "name": "创建菜单",
                        "sort": null,
                        "type": 3,
                        "parentId": 4,
                        "permission": "system:menu:create"
                    },
                    {
                        "id": 22,
                        "url": null,
                        "name": "删除菜单",
                        "sort": null,
                        "type": 3,
                        "parentId": 4,
                        "permission": "system:menu:delete"
                    },
                    {
                        "id": 23,
                        "url": null,
                        "name": "修改菜单",
                        "sort": null,
                        "type": 3,
                        "parentId": 4,
                        "permission": "system:menu:update"
                    },
                    {
                        "id": 24,
                        "url": null,
                        "name": "查询菜单",
                        "sort": null,
                        "type": 3,
                        "parentId": 4,
                        "permission": "system:menu:query"
                    }
                ],
                "parentId": 1
            },
            {
                "id": 25,
                "url": "/main/system/role",
                "name": "角色管理",
                "sort": 102,
                "type": 2,
                "children": [
                    {
                        "id": 26,
                        "url": null,
                        "name": "创建角色",
                        "sort": null,
                        "type": 3,
                        "parentId": 25,
                        "permission": "system:role:create"
                    },
                    {
                        "id": 27,
                        "url": null,
                        "name": "删除角色",
                        "sort": null,
                        "type": 3,
                        "parentId": 25,
                        "permission": "system:role:delete"
                    },
                    {
                        "id": 28,
                        "url": null,
                        "name": "修改角色",
                        "sort": null,
                        "type": 3,
                        "parentId": 25,
                        "permission": "system:role:update"
                    },
                    {
                        "id": 29,
                        "url": null,
                        "name": "查询角色",
                        "sort": null,
                        "type": 3,
                        "parentId": 25,
                        "permission": "system:role:query"
                    }
                ],
                "parentId": 1
            }
        ]
    },
    {
        "id": 9,
        "name": "商品中心",
        "type": 1,
        "url": "/main/product",
        "icon": "el-icon-goods",
        "sort": 3,
        "children": [
            {
                "id": 15,
                "url": "/main/product/category",
                "name": "商品类别",
                "sort": 104,
                "type": 2,
                "children": [
                    {
                        "id": 30,
                        "url": null,
                        "name": "创建类别",
                        "sort": null,
                        "type": 3,
                        "parentId": 15,
                        "permission": "system:category:create"
                    },
                    {
                        "id": 31,
                        "url": null,
                        "name": "删除类别",
                        "sort": null,
                        "type": 3,
                        "parentId": 15,
                        "permission": "system:category:delete"
                    },
                    {
                        "id": 32,
                        "url": null,
                        "name": "修改类别",
                        "sort": null,
                        "type": 3,
                        "parentId": 15,
                        "permission": "system:category:update"
                    },
                    {
                        "id": 33,
                        "url": null,
                        "name": "查询类别",
                        "sort": null,
                        "type": 3,
                        "parentId": 15,
                        "permission": "system:category:query"
                    }
                ],
                "parentId": 9
            },
            {
                "id": 16,
                "url": "/main/product/goods",
                "name": "商品信息",
                "sort": 105,
                "type": 2,
                "children": [
                    {
                        "id": 34,
                        "url": null,
                        "name": "创建商品",
                        "sort": null,
                        "type": 3,
                        "parentId": 16,
                        "permission": "system:goods:create"
                    },
                    {
                        "id": 35,
                        "url": null,
                        "name": "删除商品",
                        "sort": null,
                        "type": 3,
                        "parentId": 16,
                        "permission": "system:goods:delete"
                    },
                    {
                        "id": 36,
                        "url": null,
                        "name": "修改商品",
                        "sort": null,
                        "type": 3,
                        "parentId": 16,
                        "permission": "system:goods:update"
                    },
                    {
                        "id": 37,
                        "url": null,
                        "name": "查询商品",
                        "sort": null,
                        "type": 3,
                        "parentId": 16,
                        "permission": "system:goods:query"
                    }
                ],
                "parentId": 9
            }
        ]
    },
    {
        "id": 41,
        "name": "随便聊聊",
        "type": 1,
        "url": "/main/story",
        "icon": "el-icon-chat-line-round",
        "sort": 4,
        "children": [
            {
                "id": 42,
                "url": "/main/story/chat",
                "name": "你的故事",
                "sort": 108,
                "type": 2,
                "children": null,
                "parentId": 41
            },
            {
                "id": 43,
                "url": "/main/story/list",
                "name": "故事列表",
                "sort": 109,
                "type": 2,
                "children": [],
                "parentId": 41
            }
        ]
    }
]
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值