Vue3的菜单的动态渲染-基于element-plus

144 阅读1分钟

在 Vue3 中构建后台系统时,菜单通常是基于一个嵌套结构的数据来动态渲染的。我们可以设计如下的菜单结构:

一、菜单结构可以大致如下

interface MenuItem {
    name: string
    icon: string
    url: string
    children?: MenuItem[]
}
export type {MenuItem}

从这个结构可以看出,菜单具有明显的树形结构。处理这种结构时,递归组件是一个非常自然且强大的方案。

二、递归渲染的思路

我们第一步要做的,是判断当前菜单项是否存在子项(即 children)。如果存在,就使用 <el-sub-menu> 渲染;如果不存在,就使用 <el-menu-item>。 Vue 中使用 v-for 进行循环,因此我们可以在模板中通过 v-if 判断是否递归调用自身:

<template>
    <el-sub-menu v-if="item.children" :index="item.url">
        <template #title>
            <el-icon>
                <component :is="item.icon"></component>
            </el-icon>
            <span>{{ item.name }}</span>
        </template>
        <MenuItem v-for="C in item.children" :key="C.url" :item="C"></MenuItem>
    </el-sub-menu>
    <el-menu-item v-else :index="item.url">
        <el-icon>
            <component :is="item.icon"></component>
        </el-icon>
        <span>{{ item.name }}</span>
    </el-menu-item>
</template>

这段代码实现了组件调用自身,从而完成递归渲染。不过这里有一点非常关键:递归必须有终止条件,否则会导致死循环。终止条件就是当 children 为空或未定义时,不再递归调用自身。

三、总结

整个递归组件的实现思路很清晰:

  • 使用 v-if 判断是否有子菜单,决定是否递归。
  • <el-sub-menu> 对应有 children 的节点,<el-menu-item> 对应叶子节点。
  • 合理使用 component :is 渲染图标。
  • 严格处理终止条件,避免死循环。
  • 确保每个菜单项的 url 是唯一的,作为 keyindex

以上如有错误,欢迎各位进行指点