如何使用Vue.js组合式API单独切换导航栏子菜单
Vue组合式API实现导航栏子菜单单独切换
你遇到的问题核心是单个布尔变量showSubmenu同时控制了所有子菜单的显示/隐藏,导致点击任意父菜单都会触发所有子菜单同步展开/收起。下面提供两种简单可行的解决方法:
方案一:给每个菜单项添加独立的展开状态属性
直接在菜单数据中为每个项添加isOpen属性,单独控制自身子菜单的状态:
修改后的脚本代码
<script setup> import Icon from '../Shared/Icon.vue'; import { Link } from '@inertiajs/inertia-vue3'; import { ref } from 'vue'; const showDropdown = ref(false) const menu = ref([ { id: 1, name: 'dashboard', icon_name: 'dashboard', submenu: [], isOpen: false }, { id: 2, name: 'residentes', icon_name: 'down', submenu: [ { name: 'admin. residentes', icon: 'residentes' }, { name: 'admin. familiares', icon: 'family' } ], isOpen: false }, { id: 3, name: 'empleados', icon_name: 'down', submenu: [ { name: 'admin. empleados', icon: 'empleados' }, { name: 'sueldos', icon: 'sueldos' }, { name: 'jornadas de Trabajo', icon: 'jornadas' }, { name: 'Permisos', icon: 'permisos' } ], isOpen: false }, { id: 4, name: 'usuarios', icon_name: 'down', submenu: [ { name: 'admin. usuarios', icon: 'usuarios' }, { name: 'roles', icon: 'roles' }, { name: 'acceso', icon: 'premission' } ], isOpen: false }, { id: 5, name: 'finanzas', icon_name: 'down', submenu: [ { name: 'ingresos', icon: 'ingresos' }, { name: 'egresos', icon: 'egresos' } ], isOpen: false }, ]) </script>
修改后的模板代码
<nav class="" v-if="showDropdown"> <ul class=""> <li v-for="item in menu" :key="item.id" class="pb-2"> <button v-if="item.submenu.length" @click="item.isOpen = !item.isOpen"> <Icon :name="item.icon_name" class="w-5 h-5 mr-2 inline fill-slate-500" /> <span class="capitalize"> {{ item.name }}</span> </button> <Link v-else> <Icon :name="item.icon_name" class="w-5 h-5 mr-2 inline fill-slate-500" /> <span class="capitalize"> {{ item.name }}</span> </Link> <!-- 子菜单判断条件改为当前项的isOpen状态 --> <ul v-if="item.submenu.length && item.isOpen" class="pl-3 pt-1"> <li v-for="subitem in item.submenu" :key="subitem.name" class="pb-1"> <Link class="capitalize"> <Icon :name="subitem.icon" class="w-5 h-5 mr-2 inline fill-slate-500" /> {{ subitem.name }} </Link> </li> </ul> </li> </ul> </nav>
方案二:用独立变量记录当前展开的菜单ID
如果不想修改原菜单数据结构,可以用一个变量记录当前展开的菜单ID,实现互斥展开(同一时间只展开一个子菜单):
修改后的脚本代码
<script setup> import Icon from '../Shared/Icon.vue'; import { Link } from '@inertiajs/inertia-vue3'; import { ref } from 'vue'; const showDropdown = ref(false) const currentOpenMenuId = ref(null) // 记录当前展开的菜单ID const menu = ref([ { id: 1, name: 'dashboard', icon_name: 'dashboard', submenu: [] }, { id: 2, name: 'residentes', icon_name: 'down', submenu: [ { name: 'admin. residentes', icon: 'residentes' }, { name: 'admin. familiares', icon: 'family' } ] }, { id: 3, name: 'empleados', icon_name: 'down', submenu: [ { name: 'admin. empleados', icon: 'empleados' }, { name: 'sueldos', icon: 'sueldos' }, { name: 'jornadas de Trabajo', icon: 'jornadas' }, { name: 'Permisos', icon: 'permisos' } ] }, { id: 4, name: 'usuarios', icon_name: 'down', submenu: [ { name: 'admin. usuarios', icon: 'usuarios' }, { name: 'roles', icon: 'roles' }, { name: 'acceso', icon: 'premission' } ] }, { id: 5, name: 'finanzas', icon_name: 'down', submenu: [ { name: 'ingresos', icon: 'ingresos' }, { name: 'egresos', icon: 'egresos' } ] }, ]) // 切换菜单展开状态的方法 const toggleSubmenu = (menuId) => { currentOpenMenuId.value = currentOpenMenuId.value === menuId ? null : menuId } </script>
修改后的模板代码
<nav class="" v-if="showDropdown"> <ul class=""> <li v-for="item in menu" :key="item.id" class="pb-2"> <button v-if="item.submenu.length" @click="toggleSubmenu(item.id)"> <Icon :name="item.icon_name" class="w-5 h-5 mr-2 inline fill-slate-500" /> <span class="capitalize"> {{ item.name }}</span> </button> <Link v-else> <Icon :name="item.icon_name" class="w-5 h-5 mr-2 inline fill-slate-500" /> <span class="capitalize"> {{ item.name }}</span> </Link> <!-- 判断当前菜单ID是否与记录的ID一致 --> <ul v-if="item.submenu.length && currentOpenMenuId === item.id" class="pl-3 pt-1"> <li v-for="subitem in item.submenu" :key="subitem.name" class="pb-1"> <Link class="capitalize"> <Icon :name="subitem.icon" class="w-5 h-5 mr-2 inline fill-slate-500" /> {{ subitem.name }} </Link> </li> </ul> </li> </ul> </nav>
补充说明
- 方案一适合需要同时展开多个子菜单的场景,方案二适合同一时间只展开一个子菜单的场景,可根据需求选择。
- 原代码中子菜单的
:key="subitem"存在风险,因为subitem是对象,Vue建议用唯一值(如subitem.name)作为key,已在修改后的代码中调整。
内容的提问来源于stack exchange,提问作者Ubaldo Villaba
相关产品推荐
相关产品推荐

