Vue2极简教程006:实现菜单路由切换的完整方案

一、基础路由切换实现

1. 菜单组件结构

<template>
  <div class="menu-container">
    <!-- 使用router-link实现导航 -->
    <router-link 
      v-for="item in menuItems" 
      :key="item.path"
      :to="item.path"
      class="menu-item"
      active-class="active"
    >
      {{ item.title }}
    </router-link>
  </div>
</template>

<script>
export default {
  data() {
    return {
      menuItems: [
        { title: '首页', path: '/' },
        { title: '产品中心', path: '/products' },
        { title: '关于我们', path: '/about' }
      ]
    }
  }
}
</script>

<style scoped>
.menu-item {
  display: inline-block;
  padding: 10px 20px;
  cursor: pointer;
}
.active {
  border-bottom: 2px solid #42b983;
  color: #42b983;
}
</style>

2. 路由配置示例

// router/index.js
const routes = [
  {
    path: '/',
    name: 'Home',
    component: () => import('../views/Home.vue')
  },
  {
    path: '/products',
    name: 'Products',
    component: () => import('../views/Products.vue')
  },
  {
    path: '/about',
    name: 'About',
    component: () => import('../views/About.vue')
  }
]

二、进阶功能实现

1. 编程式导航控制

<template>
  <div class="menu-item" 
       v-for="item in menuItems"
       :key="item.path"
       @click="handleMenuClick(item)">
    {{ item.title }}
  </div>
</template>

<script>
export default {
  methods: {
    handleMenuClick(item) {
      // 路由跳转
      this.$router.push(item.path)
      
      // 或者带参数跳转
      // this.$router.push({
      //   name: item.name,
      //   params: { id: 123 }
      // })
      
      // 添加跳转逻辑
      if (item.requireAuth && !this.isLogin) {
        this.$router.push('/login')
      }
    }
  }
}
</script>

2. 动态菜单高亮

computed: {
  activeMenu() {
    return this.$route.path // 根据当前路由自动高亮
  }
}

三、企业级最佳实践

1. 权限菜单方案

// 过滤有权限的菜单项
computed: {
  filteredMenus() {
    return this.menuItems.filter(item => {
      return !item.meta?.requiresAuth || this.$store.getters.hasPermission
    })
  }
}

// 路由配置中添加元信息
{
  path: '/admin',
  meta: { requiresAuth: true }
}

2. 面包屑导航集成

// 面包屑组件
computed: {
  breadcrumbs() {
    const matched = this.$route.matched.filter(r => r.meta?.title)
    return matched.map(route => ({
      title: route.meta.title,
      path: route.path
    }))
  }
}

四、常见问题解决方案

1. 菜单刷新后高亮丢失

// 使用路由name替代path作为标识
activeClass() {
  return this.$route.name === this.menuItem.name ? 'active' : ''
}

2. 路由重复点击报错

// 重写router.push方法
const originalPush = VueRouter.prototype.push
VueRouter.prototype.push = function push(location) {
  return originalPush.call(this, location).catch(err => err)
}

3. 菜单动画效果

<transition name="fade">
  <router-view></router-view>
</transition>

<style>
.fade-enter-active, .fade-leave-active {
  transition: opacity 0.3s;
}
.fade-enter, .fade-leave-to {
  opacity: 0;
}
</style>

五、完整项目结构示例

src/
├── components/
│   └── Menu.vue          # 导航菜单组件
├── router/
│   ├── index.js          # 路由配置
│   └── routes.js         # 路由定义
├── views/
│   ├── Home.vue
│   ├── Products.vue
│   └── About.vue
└── store/
    └── modules/
        └── menu.js       # 菜单状态管理

六、性能优化建议

  1. 路由懒加载

    component: () => import(/* webpackChunkName: "about" */ '../views/About.vue')
  2. 菜单数据缓存

    created() {
      if (!this.$store.state.menu.loaded) {
        this.$store.dispatch('menu/fetchMenus')
      }
    }
  3. 滚动行为控制

    const router = new VueRouter({
      scrollBehavior(to, from, savedPosition) {
        return { x: 0, y: 0 }
      }
    })
扩展建议:对于复杂中后台系统,推荐使用vue-element-admin的菜单方案

通过本教程,你可以实现:

  • 声明式的菜单路由绑定
  • 灵活的权限控制方案
  • 流畅的过渡动画效果
  • 企业级的导航交互体验

添加新评论