在使用element plus 时,最初要使用的就是导航组件了,官网上看到的也就是写死的一级/二级导航,那么如何设计一个无限级且动态的导航呢?毋庸置疑,递归。废话不多说,直接看代码和效果:
代码:
目录结果
SidebarItem.vue
<template>
<el-menu-item :index="item ? item.url : ''" v-if="!item || !item.children || item.children.length === 0">
{{ item?.menuName }}
</el-menu-item>
<el-sub-menu :index="item ? item.id : ''" v-else>
<template #title>
<span class="tab">{{ item?.menuName }}</span>
</template>
<div v-for="(child, index) in item?.children" :key="index">
<template v-if="child.children && child.children.length > 0">
<sidebar-item :key="child.id" :item="child" />
</template>
<el-menu-item v-else :index="child.url">
<span class="tab sub">{{ child.menuName }}</span>
</el-menu-item>
</div>
</el-sub-menu>
</template>
<script lang="ts" setup>
import { PropType, toRefs } from 'vue';
import { MenuNode } from '../../../../model/menuNode';
const props = defineProps({
collapse: {
type: Boolean,
default: true
},
item: {
type: Object as PropType<MenuNode>,
},
});
const { item } = toRefs(props);
</script>
<style lang="scss"></style>
Index.vue
<div class="nav">
<el-scrollbar class="scrollbar">
<el-menu class="menu" @open="handleOpen" @close="handleClose" mode="horizontal" router>
<SidebarItem v-for="route in menuList" :key="route.id" :item="route"></SidebarItem>
</el-menu>
</el-scrollbar>
</div>
测试数据:
export default [
{
'id': '001',
'parentId': '0',
'menuName': '首页',
'url': '/dashboard',
'sortNo': 1,
'icon': 'Aim'
},
{
'id': '002',
'parentId': '0',
'menuName': '表格',
'url': '/charts',
'sortNo': 4,
'icon': 'ArrowDownBold'
},
{
'id': '0021',
'parentId': '002',
'menuName': '树状图',
'url': '/charts/charts1',
'sortNo': 4,
'icon': 'ArrowDownBold'
},
{
'id': '0022',
'parentId': '002',
'menuName': '饼状图',
'url': '/charts/charts2',
'sortNo': 4,
'icon': 'ArrowDownBold'
},
{
'id': '003',
'parentId': '0',
'menuName': '测试四级1',
'url': '/dashboard',
'menuType': 1,
'sortNo': 2,
'icon': 'Aim'
},
{
'id': '0031',
'parentId': '003',
'menuName': '测试四级2',
'url': '/dashboard',
'menuType': 1,
'sortNo': 2,
'icon': 'Aim'
},
{
'id': '00311',
'parentId': '0031',
'menuName': '测试四级3',
'url': '/dashboard',
'menuType': 1,
'sortNo': 2,
'icon': 'Aim'
},
{
'id': '003111',
'parentId': '00311',
'menuName': '测试四级4',
'url': '/dashboard',
'menuType': 1,
'sortNo': 2,
'icon': 'Aim'
},
];
这里需要将数组转换成树形结构,也附上代码好了(纯手工输出,有bug还望见谅):
/*
* @Author: zzh
* @Date: 2022-03-01 14:39:16
* @LastEditors: zzh
* @LastEditTime: 2022-04-10 17:13:03
* @Description: 数据转换帮助类
* @FilePath: \zh-admin\src\utils\dataConvert.ts
*/
import { MenuNode } from '../model/menuNode';
// 由于菜单数据并非一颗树,而是多棵树组成的数据,顾当成由树组成的数组的处理
const convertMenuArrToTree = (array: Array<MenuNode>) => {
const rootMenus = array.filter(x => x.parentId === '0');
const childrenMenus = array.filter(x => x.parentId !== '0');
for (let i = 0; i < rootMenus.length; i++) {
if (childrenMenus.find(x => x.parentId === rootMenus[i].id)) {
rootMenus[i].children = getRootMenuChild(rootMenus[i].id, childrenMenus);
} else {
rootMenus[i].children = [];
}
}
return rootMenus;
};
const getRootMenuChild = (id: string, childrenMenus: Array<MenuNode>): Array<MenuNode> => {
const menus = childrenMenus.filter(x => x.parentId === id);
for (let i = 0; i < menus.length; i++) {
if (childrenMenus.find(x => x.parentId === menus[i].id)) {
menus[i].children = getRootMenuChild(menus[i].id, childrenMenus);
} else {
menus[i].children = [];
}
}
return menus;
};
export {
convertMenuArrToTree,
};
展示结果: