Vue JS侧边导航下拉列表路由切换后无法自动关闭的解决方案
Vue侧边导航路由切换时自动关闭下拉菜单的解决方案
问题描述
- 带下拉列表的Vue侧边导航,从下拉列表内的路由(如
news/contact)切换到独立路由(如home/about)时,下拉列表始终保持展开状态,仅页面刷新后才会关闭。 - 尝试给
<router-view/>添加:key="$route.fullPath"强制重新渲染组件,但导致下拉列表无法正常展开。
提供的侧边导航代码
<template> <nav class="navbar-default navbar-static-side" role="navigation" > <div class="sidebar-collapse"> <ul class="nav metismenu" id="side-menu"> <li class="nav-header"> <div class="dropdown profile-element"> <a data-toggle="dropdown" class="dropdown-toggle" > <span class="clear"> <span class="block m-t-xs"> <strong class="font-bold">David Williams</strong> </span> <span class="text-muted text-xs block">Art Director <b class="caret"></b></span> </span> </a> <ul class="dropdown-menu animated fadeInRight m-t-xs"> <li><a href="#">Logout</a></li> </ul> </div> <div class="logo-element"> IN+ </div> </li> <li :class="{ 'active': $route.name === 'home' }"> <router-link :to="{ name: 'home' }"> <i class="fa fa-home"></i> <span>Home</span> </router-link> </li> <li :class="{ 'active': $route.name === 'about' }"> <router-link :to="{ name: 'about' }"> <i class="fa fa-book"></i> <span>About</span> </router-link> </li> <li :class="{ 'active': $route.name === 'news' || $route.name === 'contact'}"> <a ><i class="fa fa-bar-chart-o"></i> <span class="nav-label">Others</span><span class="fa arrow"></span></a> <ul class="nav nav-second-level collapse"> <li :class="{ 'active': $route.name === 'news' }"> <router-link :to="{ name: 'news' }"> <span>News</span> </router-link> </li> <li :class="{ 'active': $route.name === 'contact' }"> <router-link :to="{ name: 'contact' }"> <span>Contact</span> </router-link> </li> </ul> </li> </ul> </div> </nav> </template> <script> export default { name : "SideNav", } </script> <style> </style>
原因分析
原代码使用了MetisMenu插件(通过metismenu类标识),该插件依赖jQuery操作DOM来控制菜单展开收起。给<router-view/>添加:key="$route.fullPath"会强制每次路由变化都重新渲染页面组件,导致MetisMenu的初始化状态丢失,从而无法正常展开下拉菜单。
解决方案
方案一:用Vue响应式状态控制菜单(推荐,摆脱jQuery依赖)
通过Vue的响应式数据和路由监听,手动控制下拉菜单的展开/收起:
- 修改组件的
<script>部分,添加状态管理和路由监听:
export default { name : "SideNav", data() { return { // 控制Others下拉菜单的展开状态 othersMenuOpen: false } }, watch: { // 监听路由变化,自动调整菜单状态 $route(to) { if (['news', 'contact'].includes(to.name)) { this.othersMenuOpen = true; } else { this.othersMenuOpen = false; } } }, mounted() { // 初始化时根据当前路由设置菜单状态 this.othersMenuOpen = ['news', 'contact'].includes(this.$route.name); } }
- 修改模板中的下拉菜单部分,绑定状态到DOM类:
- 给触发下拉的
<a>标签添加点击事件:
<a @click="othersMenuOpen = !othersMenuOpen"> <i class="fa fa-bar-chart-o"></i> <span class="nav-label">Others</span> <span class="fa arrow"></span> </a>
- 修改二级菜单的
collapse类绑定:
<ul class="nav nav-second-level" :class="{ 'collapse': !othersMenuOpen }">
方案二:保留MetisMenu,路由变化时重置菜单
如果需要继续使用MetisMenu插件,可在路由变化时重新初始化菜单:
- 修改组件的
<script>部分:
export default { name : "SideNav", mounted() { // 初始化MetisMenu this.$nextTick(() => { $('#side-menu').metisMenu(); }); }, watch: { $route() { this.$nextTick(() => { // 销毁旧实例并重新初始化,或直接关闭展开的菜单 $('#side-menu').metisMenu('dispose'); $('#side-menu').metisMenu(); // 也可直接关闭所有展开的菜单:$('.metismenu .collapse.in').collapse('hide'); }); } } }
说明
方案一更符合Vue的响应式思想,避免了对jQuery和DOM操作的依赖,也不会出现组件重新渲染导致的状态丢失问题。
内容的提问来源于stack exchange,提问作者Isaac Hatilima
相关产品推荐
相关产品推荐

