递归竖栏菜单简单思路

文章描述了一位开发者如何利用ElementPlus框架创建一个可适应任意层级的竖栏菜单,菜单带有图标,且在展开时不会改变页面整体高度。通过使用递归组件`MenuTree.vue`实现了无限级菜单的功能,并用`el-scrollbar`确保滚动条的平滑体验。作者计划后续优化菜单高度与数据深度的关联性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

自己的项目要写一个竖栏菜单,所以记录一下思路吧,先粗糙的实现一把,有机会再把细节修饰一下

功能上就是无论这个菜单有多少层级,都能显示出来,另外,需要带图标,基于element-plus写成,当这个菜单栏点开的时候最好整个页面的高度不要有变化,最后整成了个小草稿

MyMenu.vue
<template>
    <!-- 自己写的竖栏菜单组件 -->
    <!-- <el-menu style="height: 100%;width:100%"> -->
    <el-scrollbar max-height=100%>
        <el-menu style="width: 100%;border: 0;" unique-opened :default-active="props.defaultIndex" active-text-color="#ffd04b"
            background-color="#545c64" text-color="#fff">
            <MenuTree :menu-data="props.data"></MenuTree>
        </el-menu>
    </el-scrollbar>
</template>
<script lang="ts" setup>
import MenuTree from "./MenuTree.vue"
const props=defineProps<{data:Array<any>,defaultIndex:string}>()
</script>

里面有个递归组件

MenuTree.vue
<template>
    <!-- 递归组件 -->
    <!-- 为了创建无限菜单而使用 -->
    <template v-for="value in props.menuData">
        <!-- 没有children就是一个单标签 -->
    <el-menu-item v-if="!value.children" :index="value.index">
        <template v-if="value.icon">
            <component :is="value.icon" style="width: 1rem;"></component>
        </template>
    {{ value.title }}
    </el-menu-item>
    <!-- 多标签的情况 -->
    <el-sub-menu v-else :index="value.index">
        <template #title>
            <template v-if="value.icon">
            <component :is="value.icon" style="width: 1rem;"></component>
        </template> 
            <span>{{ value.title }}</span></template>
        <MenuTree :menuData="value.children"></MenuTree>
    </el-sub-menu>

    </template>
</template>
<script setup lang="ts">
import MenuTree from "../Page1/MenuTree.vue"
const props=defineProps<{menuData:Array<any>}>()
</script>

最后写个参数挂载一下,我这边用的icon是element-plus组件自带的

<template>
    <el-container style="height: 100vh;">
        <el-header style="padding: 0;height: 5rem;">
            <div style="height: 100%;background-color:pink">
                <span>welcome to page1</span><br />
                <span>该页面用来写一个竖版menu</span>
            </div>
        </el-header>
        <el-container style="height: calc(100vh - 5rem);">
            <el-aside width="15%" style="background-color:lightblue;">
                <MyMenu :data="menuData" :default-index="defaultIndex"/>
            </el-aside>
            <el-main style="background-color:rgb(246, 199, 11);">
                <component :is="iconStr" style="width: 1rem;"></component>
            </el-main>
        </el-container>
    </el-container>
</template>
<script setup lang="ts">
import {ref} from "vue"
import { Search,Select,Close,User } from '@element-plus/icons-vue';
import MyMenu from './MyMenu.vue';
let menuData = [
    {
        title: "睡觉",
        index: "0",
        icon: Select
    },
    {
        title: "游戏",
        index: "1",
        icon: Search,
        children: [
            {
                title: "上古卷轴",
                index: "1-1",
                children: [
                    {
                        title: "上古卷轴匕首雨",
                        index: "1-1-1",
                    },
                    {
                        title: "上古卷轴天际",
                        index: "1-1-2",
                        icon: Select
                    }
                ]
            },
            {
                title: "辐射",
                index: "1-2",
                children: [
                    {
                        title: "龙万德",
                        index: "1-2-1"
                    },
                    {
                        title: "辐射新维加斯",
                        index: "1-2-2"
                    }
                ]
            }
        ]
    },
    {
        title: "美食",
        index: "2",
        icon: Close,
        children: [
            {
                title: "淮扬菜",
                index: "2-1",
                children: [
                    {
                        title: "红烧狮子头",
                        index: "2-1-1"
                    },
                    {
                        title: "猪头肉",
                        index: "2-1-2"
                    },
                ]
            },
            {
                title: "川菜",
                index: "2-2",
                children: [
                    {
                        title: "四川泡菜",
                        index: "2-2-1"
                    },
                    {
                        title: "水煮鱼",
                        index: "2-2-2"
                    },
                    {
                        title: "开水白菜",
                        index: "2-2-3"
                    },
                ]
            },
            {
                title: "粤菜",
                index: "2-3",
                children: [
                    {
                        title: "白切鸡",
                        index: "2-3-1"
                    },
                    {
                        title: "顺德鱼生",
                        index: "2-3-2"
                    },
                    {
                        title: "猪肚鸡",
                        index: "2-3-3"
                    },
                ]

            }
        ]
    },
    {
        title: "编程",
        index: "3",
        icon: User,
        children: [
            {
                title: "golang",
                index: "3-1",
                children: [
                    {
                        title: "云原生",
                        index: "3-1-1"
                    },
                    {
                        title: "gin",
                        index: "3-1-2"
                    }
                ]
            },
            {
                title: "js",
                index: "3-2"
            },
            {
                title: "python",
                index: "3-3"
            }
        ]
    }
]
// 默认index值
let defaultIndex = ref("0")
</script>

主要过程就是写了一个递归的菜单栏,然后用el-scrollbar包装了一下,以免这个菜单展开的时候把盒子高度撑开。

细节上难看了一点,此外我觉得整个菜单的高度应该和传入数组的最大深度相关,得把这个el-scrollbar组件换掉才行,先写着,有时间完善。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值