在使用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,
- };
展示结果: