全局路由:
export let routerArray = [
{
path: '/login',
component: () => import('@/views/login/index.vue'),
name: 'login',
meta:{
title:'登录',
hidden: false
}
},
{
path: '/',
component: () => import('@/layout/index.vue'),
name: 'layout',
meta:{
title:'总页面',
hidden: true
},
children: [
{
path: 'home',
component: () => import('@/views/home/index.vue'),
name: 'home',
meta:{
title:'首页',
hidden: false
}
},
{
path: 'ppp',
component: () => import('@/views/ppp.vue'),
name: 'ppp',
meta:{
title:'ppp',
hidden: false
}
}
]
},
{
path: '/404',
component: () => import('@/views/404/index.vue'),
name: 'Any',
meta:{
title:'404',
hidden: true
}
},
{
path: '/:pathMatch(.*)*',
redirect: '/404',
meta:{
title:'404',
hidden: true
}
}
]
pinia的user存储对象:
import { defineStore } from 'pinia';
import {login} from '@/api/user'
import type{loginDto,resPonseVo} from '@/api/user/type'
import {routerArray} from '@/router/staticRouter.ts'
export let useUserStore=defineStore('User',{
state: ()=>{
return {
token : localStorage.getItem('TOKEN'),
allRoute:routerArray
}
},
actions:{
async userLogin(loginDto1:loginDto){
let loginRes:resPonseVo= await login(loginDto1)
if(loginRes.code==200){
this.token=(loginRes.data.token as string);
localStorage.setItem('TOKEN',(loginRes.data.token as string))
}else{
return Promise.reject(new Error(loginRes.data.message))
}
}
}
})
父组件:
//父级组件
<template>
<div class="layout-all">
<div class="layout-sider">
<Logo></Logo>
<el-scrollbar class="scrollbar">//为了实现在菜单特别多时,可以生成滚动条
<el-menu background-color="#1089dc" text-color="#ffffff" active-text-color="#181818">
//封装的菜单组件
<Menu :menuList="User.allRoute"></Menu>
</el-menu>
</el-scrollbar>
</div>
<div class="layout-header">
</div>
<div class="layout-main">
<p style="height: 10000px; background-color: black;"></p>
</div>
</div>
</template>
<script setup lang="ts">
import Logo from '@/components/logo/index.vue'
import {useUserStore} from '@/store/modules/user'
import Menu from '@/layout/menu/index.vue'
//pinia中存储了路由对象数组
let User=useUserStore();
console.log(User.allRoute)
</script>
<style lang="scss" scoped>
.layout-all {
width: 100%;
height: 100vh;
.layout-sider {
width: $layout-width;
height: 100vh;
background-color: #1089dc;
.scrollbar {
width: 100%;
height: calc(100vh - $logo-height);
.el-menu{
border-right: none;
}
}
}
.layout-header {
position: fixed;
width: calc(100% - $layout-width);
height: 50px;
background-color: #2c797e;
top: 0px;
left: $layout-width ;
}
.layout-main {
position: absolute;
width: calc(100% - $layout-width);
height: calc(100vh - 50px);
background-color: aqua;
left: $layout-width;
top: 50px;
padding: 20px;
overflow: auto;
}
}
</style>
封装的菜单子组件:
<template>
<template v-for="item in menuList" :key="item.path">
<template v-if="!item.children">
<el-menu-item v-if="!item.meta.hidden" :index="item.path" @click="toRoute(item.path)">
<el-icon>
<component :is="item.meta.icon"></component>
</el-icon>
<template #title>
<span>{{ item.meta.title }}</span>
</template>
</el-menu-item>
</template>
<template v-if="item.children && item.children.length == 1">
<el-menu-item v-if="!item.children[0].meta.hidden" :index="item.children[0].path" @click="toRoute(item.children[0].path)">
<el-icon>
<component :is="item.children[0].meta.icon"></component>
</el-icon>
<template #title>
<span>{{ item.children[0].meta.title }}</span>
</template>
</el-menu-item>
</template>
<el-sub-menu v-if="item.children && item.children.length > 1" :index="item.path">
<template #title>
<el-icon>
<component :is="item.meta.icon"></component>
</el-icon>
<span>{{ item.meta.title }}</span>
</template>
<Menu :menuList="item.children"></Menu>
</el-sub-menu>
</template>
</template>
<script setup lang="ts">
import Menu from './index.vue'
import { useRouter } from 'vue-router';
let router = useRouter()
function toRoute(path: any) {
router.push(path);
}
defineProps(['menuList'])
</script>
<style lang="scss" scoped></style>
这里实现无限嵌套的关键在于最后一个判断,如果是存在子集且大于1时,则引入组件本身,递归循环下去,并且在路由对象中定义了一个meta,里边一个菜单名称,一个是否隐藏,来实现菜单的动态显示