Element Plus/vue3 无限级导航实现

2022-04-27  本文已影响0人  张中华

在使用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,
};

展示结果:


上一篇 下一篇

猜你喜欢

热点阅读