Vue.js 2多级下拉菜单失效无报错,如何实现嵌套下拉菜单?
Vue.js 2 多级下拉菜单实现方案
原代码核心问题
- 所有嵌套子菜单共用同一个
submenuOpen状态变量,点击任意子菜单会触发全局状态切换,导致多级菜单无法独立控制展开/收起。 - 缺少点击页面外部区域关闭菜单的逻辑,菜单展开后只能通过原按钮关闭,交互体验差。
- 依赖的Bootstrap类缺少对应样式支撑,导致菜单布局异常(比如默认显示而非隐藏)。
修正实现方案
关键改进点
- 为每个子菜单维护独立状态:用对象存储不同层级子菜单的状态,通过唯一标识区分控制。
- 添加外部点击关闭逻辑:利用事件冒泡机制,点击页面其他区域时关闭所有下拉菜单。
- 补充基础样式:内置下拉菜单必要样式,避免依赖外部CSS库导致的显示问题。
完整修正代码
<template> <div class="container" @click="closeAllDropdowns"> <div class="dropdown" @click.stop> <button class="btn btn-default" @click="toggleDropdown"> Tutorials <span class="caret"></span> </button> <ul class="dropdown-menu" v-show="dropdownOpen"> <li><a href="#">HTML</a></li> <li><a href="#">CSS</a></li> <li class="dropdown-submenu" @click.stop> <a href="#" @click="toggleSubmenu('level2')"> New dropdown <span class="caret"></span> </a> <ul class="dropdown-menu" v-show="submenuStates.level2"> <li><a href="#">2nd level dropdown</a></li> <li><a href="#">2nd level dropdown</a></li> <li class="dropdown-submenu" @click.stop> <a href="#" @click="toggleSubmenu('level3')"> Another dropdown <span class="caret"></span> </a> <ul class="dropdown-menu" v-show="submenuStates.level3"> <li><a href="#">3rd level dropdown</a></li> <li><a href="#">3rd level dropdown</a></li> </ul> </li> </ul> </li> </ul> </div> </div> </template> <script> export default { data() { return { dropdownOpen: false, // 用对象存储每个子菜单的独立状态 submenuStates: { level2: false, level3: false } }; }, methods: { toggleDropdown() { this.dropdownOpen = !this.dropdownOpen; // 展开主菜单时重置所有子菜单状态(可选) if (this.dropdownOpen) { this.submenuStates = { level2: false, level3: false }; } }, toggleSubmenu(key) { this.submenuStates[key] = !this.submenuStates[key]; // 展开当前子菜单时关闭其他同级子菜单(可选) Object.keys(this.submenuStates).forEach(k => { if (k !== key) this.submenuStates[k] = false; }); }, closeAllDropdowns() { this.dropdownOpen = false; this.submenuStates = { level2: false, level3: false }; } } }; </script> <style> /* 基础下拉菜单样式,无需依赖外部库 */ .dropdown { position: relative; display: inline-block; } .dropdown-menu { position: absolute; top: 100%; left: 0; z-index: 1000; min-width: 160px; padding: 5px 0; margin: 2px 0 0; font-size: 14px; list-style: none; background-color: #fff; border: 1px solid #ccc; border-radius: 4px; box-shadow: 0 6px 12px rgba(0,0,0,.175); display: none; } /* 配合v-show控制显示 */ .dropdown-menu[v-show="true"] { display: block; } .dropdown-submenu { position: relative; } .dropdown-submenu .dropdown-menu { top: 0; left: 100%; margin-top: -1px; } .btn { display: inline-block; padding: 6px 12px; font-size: 14px; border: 1px solid #ccc; border-radius: 4px; background-color: #fff; cursor: pointer; } .caret { display: inline-block; width: 0; height: 0; margin-left: 2px; vertical-align: middle; border-top: 4px solid; border-right: 4px solid transparent; border-left: 4px solid transparent; } </style>
内容的提问来源于stack exchange,提问作者dkrks
相关产品推荐
相关产品推荐

