Tailwind+Vue-Router下拉菜单点击router-link不关闭问题求助
我之前也遇到过一模一样的问题,先给你捋清楚原因:你现在的下拉菜单是靠纯CSS的hover伪类控制显示的——.dropdown:hover .dropdown-menu { display: block; }。点击普通<a>标签时页面会刷新,组件重新渲染,hover状态自然消失;但<router-link>是单页面跳转,页面不会刷新,只要鼠标还停留在dropdown容器(按钮或菜单区域)内,hover状态就会一直保持,菜单也就不会自动关闭。
下面给你两种靠谱的解决方案,优先推荐第一种,更贴合Vue的响应式开发思路:
方案一:用Vue状态控制菜单显示(推荐)
放弃纯CSS的hover控制,改用Vue的响应式状态管理菜单的显示隐藏,这样我们可以在点击router-link时手动触发关闭,同时保留hover打开的交互体验。
步骤如下:
- 在组件的
data中添加状态变量:
data() { return { isDropdownOpen: false } }
- 修改组件模板,用状态绑定替代CSS hover,同时给router-link添加点击事件关闭菜单:
<div class="dropdown inline-block relative sm:ml-20" @mouseenter="isDropdownOpen = true" @mouseleave="isDropdownOpen = false"> <button class="text-gray-700 font-normal py-2 px-4 rounded inline-flex items-center"> <span class="mr-1 cursor-default">Vita</span> </button> <!-- 用:class绑定控制菜单的显示隐藏 --> <ul class="w-32 dropdown-menu absolute text-gray-700 pt-1 shadow-lg z-10" :class="{ hidden: !isDropdownOpen }"> <li> <!-- 把样式直接加在router-link上,不要嵌套a标签(嵌套a不符合HTML规范) --> <router-link to="/biografia" class="rounded-t bg-white hover:bg-gray-200 py-2 px-4 block whitespace-no-wrap text-sm" @click="isDropdownOpen = false" > Bio </router-link> </li> <li> <router-link to="/tour" class="bg-white hover:bg-gray-200 py-2 px-4 block whitespace-no-wrap text-sm" @click="isDropdownOpen = false" > Tour </router-link> </li> <li> <router-link to="/foto" class="bg-white hover:bg-gray-200 py-2 px-4 block whitespace-no-wrap text-sm" @click="isDropdownOpen = false" > Foto </router-link> </li> <li> <router-link to="/video" class="rounded-b bg-white hover:bg-gray-200 py-2 px-4 block whitespace-no-wrap text-sm" @click="isDropdownOpen = false" > Video </router-link> </li> </ul> </div>
- 移除原来的CSS hover规则:
/* 删除这行代码 */ .dropdown:hover .dropdown-menu { display: block; }
调整后,菜单会在鼠标进入dropdown区域时打开,离开时关闭;点击任何router-link菜单项时,都会手动将isDropdownOpen设为false,菜单立刻关闭的同时完成单页面跳转。
方案二:保留CSS hover,点击时强制关闭
如果不想大幅改动现有代码,也可以通过JS在点击router-link时强制让dropdown失去hover状态:
- 在组件中添加方法:
methods: { closeDropdown() { // 获取dropdown元素,触发mouseleave事件关闭菜单 const dropdownEl = this.$el.querySelector('.dropdown'); if (dropdownEl) { dropdownEl.dispatchEvent(new Event('mouseleave')); } } }
- 给每个router-link绑定点击事件:
<router-link to="/biografia" @click="closeDropdown"> <a class="rounded-t bg-white hover:bg-gray-200 py-2 px-4 block whitespace-no-wrap text-sm"> Bio </a> </router-link>
不过这种方法依赖DOM操作,灵活性不如状态控制,而且你原代码中router-link嵌套a标签的问题依然存在(HTML规范不允许a标签嵌套a标签),所以还是更推荐方案一。
最后提个小细节:你原代码里<router-link>内部嵌套了<a>标签,这是不符合HTML规范的——router-link默认会渲染成a标签,嵌套后会出现a标签嵌套a的情况,浏览器可能会解析异常,建议替换成span,或者直接把样式加在router-link上。
内容的提问来源于stack exchange,提问作者nicoblue

