vue3 ts element plus 递归遍历实现多级菜单

149 阅读2分钟

项目地址:gitee.com/luobf22/vue…

摘要

element plus的菜单只能到达二级,有的时候需求可能达到多级菜单,因此编写此文章,学习如何开发多级菜单组件

菜单组件

<template>
  <div>
    <el-menu
      active-text-color="#ffd04b"
      background-color="#545c64"
      class="el-menu-vertical-demo"
      default-active="2"
      text-color="#fff"
    >
    //将所有菜单一起遍历传递给子组件,让子组件判断菜单是否有子菜单
      <MenuComponent
        v-for="menuItem in MenuList"
        :key="menuItem.name"
        :menuItem="menuItem"
      ></MenuComponent>
    </el-menu>
  </div>
</template>

<script lang="ts">
import { defineComponent, reactive } from "vue";
import MenuComponent from "./MenuComponent.vue";
export default defineComponent({
  name: "Menu",
  setup() {
    const MenuList = reactive([
      {
        path: "./",
        name: "Home",
        title: "主页",
      },
      {
        path: "./vue",
        name: "Vue",
        title: "vue学习",
        childrens: [
          {
            path: "/vueIdRouter",
            name: "VueIdRouter",
            title: "vue-动态传值",
            childrens: [
              {
                path: "/vueIdRouter-子菜单",
                name: "VueIdRouter-子菜单",
                title: "vue-动态传值-子菜单",
                childrens: [
                  {
                    path: "/vueIdRouter-子菜单22",
                    name: "VueIdRouter-子菜单22",
                    title: "vue-动态传值-子菜单22",
                  },
                ],
              },
            ],
          },
          {
            path: "/vueIdRouter-没有子菜单",
            name: "VueIdRouter-没有子菜单",
            title: "vue-动态传值-没有子菜单",
          },
          {
            path: "/vueIdRouter3",
            name: "VueIdRouter3",
            title: "vue-动态传值3",
            childrens: [
              {
                path: "/vueIdRouter-子菜单3",
                name: "VueIdRouter-子菜单3",
                title: "vue-动态传值-子菜单3",
                childrens: [
                  {
                    path: "/vueIdRouter-子菜单33",
                    name: "VueIdRouter-子菜单33",
                    title: "vue-动态传值-子菜单33",
                  },
                ],
              },
            ],
          },
        ],
      },
    ]);
    return {
      MenuList,
      MenuComponent,
    };
  },
});
</script>

菜单遍历组件

<template>
//有子菜单
  <el-sub-menu
    v-if="menuItem.childrens && menuItem.childrens.length"
    :index="menuItem.name"
  >
    <template #title>
      {{ menuItem.title }}
    </template>
    //有子菜单 调用当前组件
    <MenuComponent
      v-for="child in menuItem.childrens"
      :key="child.name"
      :menuItem="child"
    ></MenuComponent>
  </el-sub-menu>
  //没有子菜单
  <el-menu-item v-else :index="menuItem.name">
    {{ menuItem.title }}
  </el-menu-item>
</template>

<script lang="ts">
import { defineComponent } from "vue";
//定义菜单对象的数据类型
interface MenuItem {
  path: string;
  name: string;
  title: string;
 //子菜单可能存在也可能不存在,子菜单里还有相同的数据类型
 //注意:
 //这里没有问号会导致Menu.vue报错,因为没有问号就规定传递的菜单对象必有子菜单,如果没有MenuItem,当前组件MenuComponent.vue就会报错,因为那就规定子菜单必是空对象,但是子菜单除了可能为空,也可能有数据
  childrens?: MenuItem[];
}
export default defineComponent({
  name: "MenuComponent",
  //通过props接受数据
  props: {
    menuItem: {
    //断言绑定类型
      type: Object as () => MenuItem,
      //require:true 是一种约束,确保组件在使用时能够正确地接收必要的数据,有助于在开发阶段捕获潜在的错误。
      required: true,
    },
  },
});
</script>