1. 组件
src\components\menuTree\index.vue
<template>
<template v-for="item in menuList">
<!-- 分为两种方式渲染:有子菜单和没有子菜单-->
<!-- 没有子菜单-->
<el-menu-item :index="item.path" v-if="item.children.length == 0" :key="item.path">
<el-icon v-if="item.icon"><svg-icon slot="prefix" :name="item.icon" width="18px"
height="18px" /></el-icon>
<span>{{ item.menuName }}</span>
</el-menu-item>
<el-sub-menu :index="item.path" v-if="item?.children?.length > 0">
<template #title>
<el-icon v-if="item.icon"><svg-icon slot="prefix" :name="item.icon" width="18px"
height="18px" /></el-icon>
<span>{{ item.menuName }}</span>
</template>
<!-- 有子菜单的继续遍历(递归)-->
<MenuTree :menuList="item.children"></MenuTree>
</el-sub-menu>
</template>
</template>
<script setup lang="ts">
// 声明 props - 对象格式 在script 中不使用props拿不到数据, <template>中自动解构
const props = defineProps({
menuList: Array<any>
})
</script>
<script lang="ts">
export default {
name: "MenuTree"
}
</script>
注1: 组件自递时要导出
注2: 这里使用的图标是之前自定义的图标组件
<script lang="ts">
export default {
name: "MenuTree"
}
</script>
2 . 使用示例
在父组件中:
数据根据自己的相应修改
<template>
<div class="menu-container">
<div class="up-title" v-if="!isCollapse">
<!-- <div>
<svg-icon name="" width="20px" height="20px" />
</div> -->
<div class="title-text">{{ !isCollapse ? "Vue3 boot3 快速开发平台" : "" }}</div>
</div>
<div class="down-menu">
<el-menu :default-active="route.path" class="el-menu-vertical-demo" :collapse="isCollapse" :router="true"
:collapse-transition="false">
<MenuTree :menuList="menuList"></MenuTree>
</el-menu>
</div>
</div>
</template>
<script setup lang="ts">
import { onMounted} from 'vue'
//渲染菜单的组件
import MenuTree from "@/components/menuTree/index.vue"
import { useMenuStore } from '@/stores/menu.js'
import { useRoute } from 'vue-router'
const menuStore = useMenuStore()
const route = useRoute()
// 获取pinia的缓存的菜单数据
const menuList = menuStore.menuList
const props = defineProps({
isCollapse: Boolean
})
</script>
<style lang="scss">
.menu-container {
display: flex;
flex-direction: column;
height: 100vh;
.up-title {
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
height: 5vh;
// padding: 3px;
/* 内边距 */
border-bottom: 2px solid;
border-right: 1px solid;
/* 设置下边框宽度和样式 */
border-color: #f5f5f5;
.title-text {
display: inline-block;
vertical-align: middle;
/* 文字与图片垂直居中对齐 */
font-weight: bold;
/* 加粗文字 */
font-size: 13px;
margin-left: 5px;
}
}
.down-menu {
flex-grow: 1;
}
}
.el-menu-vertical-demo {
height: 100%;
overflow: auto;
}
</style>
3. 说明
- 监听事件说明
因为使用递归构造组件, 使用el-menu-item 添加事件会传播到el-sub-menu,会影响emit 向父组件发送数据,
事件stop也会影响emit, 所以后续面包屑,tabs数据通过监听路由变化获取