- 导航菜单主页面
<template>
<div :class="collapsed ? 'shrink' : 'open'">
<a-button
type="primary"
@click="toggleCollapsed"
class="buttonOpen"
:style="{ marginLeft: collapsed ? '18px' : '10px' }"
>
<p v-if="collapsed" title="展开菜单"><MenuUnfoldOutlined /></p>
<p v-else title="收拢菜单"><MenuFoldOutlined /></p>
</a-button>
<a-menu
v-model:openKeys="openKeys"
mode="inline"
theme="dark"
:inline-collapsed="collapsed"
class="menu-class"
>
<template v-for="item in routerList" :key="item.name">
<template v-if="item.meta.hidden"> // 首先根据meta里面的hidden属性判断是否显示,比如登录页面就不需要显示
<template v-if="!item.children"> // 如果没有子菜单,显示的就应该是第一层菜单
<a-menu-item :key="item.name">
<PieChartOutlined />
<span>{{ item.meta.title }}</span>
</a-menu-item>
</template>
<template v-else> // 调用递归子组件
<sub-menu :menu-info="item" :key="item.name" />
</template>
</template>
</template>
</a-menu>
</div>
</template>
<script lang="ts">
import { defineComponent, reactive, toRefs } from "vue";
import {
MenuFoldOutlined,
MenuUnfoldOutlined,
PieChartOutlined,
} from "@ant-design/icons-vue";
import SubMenu from "./SubMenu.vue";
import { useRoute, useRouter } from "vue-router";
export default defineComponent({
components: {
"sub-menu": SubMenu,
MenuFoldOutlined,
MenuUnfoldOutlined,
PieChartOutlined,
},
setup() {
const router = useRouter();
const route = useRoute();
const data = reactive({
collapsed: false,
routerList: router.options.routes,
openKeys: [],
selectedKeys: [],
toggleCollapsed() {
if (!data.collapsed) (data.openKeys as any) = [];
else (data.openKeys as any) = route.fullPath.split("/").slice(1);
data.collapsed = !data.collapsed;
},
});
return {
...toRefs(data),
};
},
});
</script>
<style lang="scss" scoped>
.shrink {
width: 80px;
transition: width 0.3s;
}
.open {
width: 256px;
transition: width 0.3s;
}
.menu-class {
height: calc(100vh - 50px);
}
.buttonOpen {
margin: 6px 0;
// transition: all 0.3 !important;
}
</style>
- 递归子组件
<template>
<a-sub-menu :key="menuInfo.name" v-bind="$attrs">
<template #title>
<span>
<MailOutlined />
<span>{{ menuInfo.meta.title }}</span>
</span>
</template>
<template v-for="item in menuInfo.children" :key="item.name">
<template v-if="item.meta.hidden">
<template v-if="!item.children">
<a-menu-item :key="item.name">
<PieChartOutlined />
<span>
{{ item.meta.title }}
</span>
</a-menu-item>
</template>
<template v-else> // 递归调用自身组件
<sub-menu :menu-info="item" :key="item.name" />
</template>
</template>
</template>
</a-sub-menu>
</template>
<script lang="ts">
import { defineComponent } from "vue";
import { Menu } from 'ant-design-vue';
import { PieChartOutlined, MailOutlined } from "@ant-design/icons-vue";
export default defineComponent({
name: "SubMenu",
components: {
PieChartOutlined,
MailOutlined,
},
props: {
...Menu.SubMenu.props,
menuInfo: {
type: Object,
default: () => ({}),
},
},
});
</script>
<style lang="scss" scoped></style>
截图一个router的写法
如果有根据后台获取展示菜单,则继续在meta中添加对应属性匹配即可,类似图上umark。