1,创建菜单所以对应的页面
2,创建页面所对应的路由
这里使用了一个插件 coderwhy
npm i coderwhy -g
使用这个命令符可以快速搭建出上述页面
// coderwhy add3page 文件名 -d 对应目录路径
coderwhy add3page dashboard -d src/views/main/analysis/dashboard
3,创建map-menus.ts文件
import { RouteRecordRaw } from 'vue-router'
export function mapMenusToRoutes(userMenus: any[]): RouteRecordRaw[] {
const routes: RouteRecordRaw[] = []
const allRoutes: RouteRecordRaw[] = []
const routeFiles = require.context('../router/main', true, /\.ts/)
// console.log('routeFiles', routeFiles.keys())
//拿到所有页面文件的路径
routeFiles.keys().forEach((key: any) => {
//根据路径拿到所有页面文件
const route = require('../router/main' + key.split('.')[1])
allRoutes.push(route.default) //default这个属性对应的就是export default 的 default,如果你写成 export xx = {} 那这里就取route.xx
//也就是说我们把每个文件中导出的对象都push到allRoutes中了
})
const _recurseGetRoute = (menus: any[]) => {
for (const menu of menus) {
if (menu.type === 2) {
//根据给的权限菜单 匹配出所需要的菜单的文件
const route = allRoutes.find((route) => route.path === menu.url)
if (route) {
routes.push(route)
}
} else {
_recurseGetRoute(menu.children)
}
}
}
_recurseGetRoute(userMenus)
return routes
}
然后在你对应想要获取路由表的地方使用map-menus.ts文件中导出的mapMenusToRoutes函数就可以得到路由表,我的首页叫做mian
//动态获取路由
const routes = mapMenusToRoutes(userMenus)
// 将routes => router.main.children
routes.forEach((route) => {
router.addRoute('main', route)
})
参考:
import { createRouter, createWebHashHistory, RouteRecordRaw } from 'vue-router'
import localCache from '@/utils/cache'
const routes: Array<RouteRecordRaw> = [
{
path: '/',
redirect: 'main'
},
{
path: '/login',
name: 'login',
component: () =>
import(/* webpackChunkName: "about" */ '@/views/login/index.vue')
},
{
path: '/main',
name: 'main',
component: () => import('@/views/main/index.vue')
}
]
const router = createRouter({
history: createWebHashHistory(),
routes
})
router.beforeEach((to) => {
if (to.path !== '/login') {
return localCache.getItem('token') ? true : '/login'
}
})
export default router
然后菜单组件:
<template>
<div class="nav-menu">
<div class="logo">
<img class="img" src="~@/assets/img/logo.svg" alt="logo" />
<span v-if="!collapse" class="title">Vue3+TS</span>
</div>
<el-menu
default-active="1"
class="el-menu-vertical"
:collapse="collapse"
background-color="#0c2135"
text-color="#b7bdc3"
active-text-color="#0a60bd"
>
<template #title>
<i class="el-icon-delete"></i> <span>Navigator One</span>
</template>
<!-- 有子菜单 -->
<template v-for="menuItem in userMenus" :key="menuItem.id">
<template v-if="menuItem.type === 1">
<el-sub-menu :index="menuItem.id + ''">
<template #title>
<i v-if="menuItem.icon" :class="menuItem.icon"></i>
<span>{{ menuItem.name }}</span>
</template>
<template v-for="menu in menuItem.children" :key="menu.id">
<el-menu-item
:index="menu.id + ''"
@click="handleMenuItemClick(menu)"
>
<i v-if="menu.icon" :class="menu.icon"></i>
<span>{{ menu.name }}</span>
</el-menu-item>
</template>
</el-sub-menu>
</template>
<!-- 无子菜单 -->
<template v-else-if="menuItem.type === 2">
<el-menu-item :index="menuItem.id + ''">
<i v-if="menuItem.icon" :class="menuItem.icon"></i>
<span> {{ menuItem.name }}</span>
</el-menu-item>
</template>
</template>
</el-menu>
</div>
</template>
<script lang="ts">
import { defineComponent, computed } from 'vue'
import { useStore } from '@/store'
import router from '@/router'
export default defineComponent({
name: 'nav-menu',
props: {
collapse: {
type: Boolean,
default: false
}
},
setup() {
const store = useStore()
const userMenus = computed(() => store.state.login.userMenus)
const handleMenuItemClick = (menu: any) => {//在点击menu-item的时候push对应路由就行啦~
router.push(menu.url)
}
return {
userMenus,
handleMenuItemClick
}
}
})
</script>
<style scoped lang="less">
.el-menu {
width: 250px;
margin: 0 auto;
}
.nav-menu {
height: 100%;
background-color: #001529;
.logo {
display: flex;
height: 28px;
padding: 12px 10px 8px 10px;
flex-direction: row;
justify-content: flex-start;
align-items: center;
.img {
height: 100%;
margin: 0 10px;
}
.title {
font-size: 16px;
font-weight: 700;
color: white;
}
}
.el-menu {
border-right: none;
}
// 目录
.el-submenu {
background-color: #001529 !important;
// 二级菜单 ( 默认背景 )
.el-menu-item {
padding-left: 50px !important;
background-color: #0c2135 !important;
}
}
::v-deep .el-submenu__title {
background-color: #001529 !important;
}
// hover 高亮
.el-menu-item:hover {
color: #fff !important; // 菜单
}
.el-menu-item.is-active {
color: #fff !important;
background-color: #0a60bd !important;
}
}
.el-menu-vertical:not(.el-menu--collapse) {
width: 100%;
height: calc(100% - 48px);
}
</style>
数据返回是这样哒:
最后长这样: