Vue2中如何动态构建无限层级嵌套菜单组件树?
构建无限层级嵌套菜单的最优方案
你当前用v-html的方式行不通——Vue不会编译v-html渲染的内容,里面的@click="sayHello()"根本不会绑定到组件的方法上,点击完全没反应。
构建嵌套菜单的最优方案是用递归组件:Vue允许组件自身调用自身,完美适配树形结构的嵌套需求。
具体实现步骤
1. 定义菜单数据结构
先准备树形结构的菜单数据,每个节点包含显示文本、子菜单(可选)、点击回调(可选):
const menuData = [ { label: "一级菜单1", click: () => console.log("点击一级菜单1"), children: [ { label: "二级菜单1-1", children: [ { label: "三级菜单1-1-1", click: () => console.log("点击三级菜单1-1-1") } ] }, { label: "二级菜单1-2", click: () => console.log("点击二级菜单1-2") } ] }, { label: "一级菜单2", click: () => console.log("点击一级菜单2") } ];
2. 编写递归组件
给组件设置name选项(必须,否则无法递归调用),模板里渲染当前菜单项,同时判断是否有子菜单,有就递归渲染:
<template> <ul class="menu-list"> <li v-for="(item, index) in menuItems" :key="index" class="menu-item"> <div class="menu-label" @click="handleClick(item)"> {{ item.label }} <!-- 有子菜单时显示展开/折叠图标 --> <span v-if="item.children" class="arrow">▼</span> </div> <!-- 递归渲染子菜单,通过展开状态控制显示 --> <menu-item v-if="item.children && item.expanded" :menu-items="item.children" /> </li> </ul> </template> <script> export default { name: "MenuItem", // 必须命名,才能递归调用自身 props: { menuItems: { type: Array, required: true } }, methods: { handleClick(item) { // 执行节点自带的点击回调 if (item.click) item.click(); // 有子菜单则切换展开状态 if (item.children) { item.expanded = !item.expanded; } } } }; </script> <style scoped> .menu-list { list-style: none; padding-left: 20px; margin: 0; } .menu-item { margin: 8px 0; } .menu-label { cursor: pointer; padding: 4px; } .arrow { margin-left: 8px; font-size: 12px; } </style>
3. 在父组件中使用
把根菜单数据传给递归组件即可:
<template> <div class="menu-container"> <menu-item :menu-items="menuData" /> </div> </template> <script> import MenuItem from "./MenuItem.vue"; export default { components: { MenuItem }, data() { return { menuData: [ // 放入之前定义的菜单数据 ] }; } }; </script>
补充说明
- 展开/折叠逻辑:直接把
expanded状态存在菜单数据里,简单直观,也可以改用组件内部的响应式状态管理。 - Vue 3 Composition API写法:逻辑类似,只需把props和方法放到
setup里,注意要单独加<script>块给组件命名:
<template> <!-- 模板和之前一致 --> </template> <script> export default { name: "MenuItem" }; </script> <script setup> import { defineProps } from 'vue'; const props = defineProps({ menuItems: { type: Array, required: true } }); const handleClick = (item) => { if (item.click) item.click(); if (item.children) { item.expanded = !item.expanded; } }; </script>
内容的提问来源于stack exchange,提问作者TheMan68
相关产品推荐
相关产品推荐

