Vuetify v-menu键盘导航异常:回车触发子菜单开合不符合预期
使用键盘导航Vuetify嵌套v-menu时,首次按下回车可以打开子菜单,但再次按下回车会直接关闭该子菜单——即便子菜单下还有下级菜单,这个行为不符合预期。
问题原因
v-menu默认的激活器回车事件是**切换(toggle)**状态:第一次触发打开菜单,第二次触发关闭。但嵌套场景下,我们需要菜单打开后,回车操作应该聚焦到子菜单内容,而非关闭父菜单。
解决方案
重写激活器的回车事件逻辑,拦截默认的toggle行为:当菜单未打开时,回车触发打开;当菜单已打开时,跳过关闭动作,直接将焦点移至子菜单的第一个可交互元素。
修改后的核心代码如下:
<v-menu :close-on-content-click="false" :offset-x='isOffsetX' :offset-y='isOffsetY' :open-on-hover='isOpenOnHover' :transition='transition' :value="openMenu"> <template v-slot:activator="{ on }"> <v-btn v-if='icon' :color='color' @mousedown="on.mousedown" @keydown.enter="handleEnter"> <v-icon>{{ icon }}</v-icon> </v-btn> <v-list-item v-else-if='isSubMenu' class='d-flex justify-space-between' @mousedown="on.mousedown" @keydown.enter="handleEnter"> {{ name }}<div class="flex-grow-1"></div><v-icon>mdi-chevron-right</v-icon> </v-list-item> <v-btn v-else :color='color' @mousedown="on.mousedown" @keydown.enter="handleEnter" @click="openMenu = true" text >{{ name }}</v-btn> </template> <v-list ref="menuList"> <template v-for="(item, index) in menuItems"> <v-divider v-if='item.isDivider' :key='index' /> <dan-menu v-else-if='item.menu' :key='index' :name='item.name' :menu-items='item.menu' @dan-menu-click='emitClickEvent' :is-open-on-hover=false :is-offset-x=true :is-offset-y=false :is-sub-menu=true /> <v-list-item v-else :key='index' @click='emitClickEvent(item)'> <v-list-item-title>{{ item.name }}</v-list-item-title> </v-list-item> </template> </v-list> </v-menu>
在组件的methods中添加事件处理函数:
methods: { handleEnter(e) { e.preventDefault(); // 阻止默认toggle行为 if (!this.openMenu) { this.openMenu = true; // 菜单打开后延迟聚焦到子菜单第一个元素 this.$nextTick(() => { const firstItem = this.$refs.menuList?.$el.querySelector('[tabindex="0"]'); firstItem?.focus(); }); } else { // 菜单已打开时,直接聚焦到子菜单第一个元素 const firstItem = this.$refs.menuList?.$el.querySelector('[tabindex="0"]'); firstItem?.focus(); } }, emitClickEvent(item) { this.$emit('dan-menu-click', item); } }
关键说明
- 替换
v-on="on"为拆分的@mousedown="on.mousedown"和自定义回车事件,保留鼠标点击的默认行为,只修改键盘回车逻辑。 - 通过
e.preventDefault()阻止v-menu默认的回车toggle动作。 - 菜单打开后,利用
$nextTick确保DOM渲染完成,再聚焦到子菜单的第一个可交互元素,保证键盘导航的连贯性。
内容的提问来源于stack exchange,提问作者Kenneth
相关产品推荐
相关产品推荐

