ElementUI之菜单(Menu)的使用方式

 更新时间:2025年08月26日 09:26:59   作者:xrkhy  
文章介绍Vue项目中ElementUI菜单默认精确路由匹配,与router-link的模糊匹配不同,提供三种解决方案:计算属性、高阶组封装、子菜单递归,并根据项目复杂度推荐使用方式

项目创建

创建项目

我的node.js使用的是20.18.0版本

我的 @vue/cli使用的是5.0.8版本

  • 新建空白文件夹输入cmd打开命令行窗口

  • 执行如下指令
vue create elementui-draw-pages
  • 勾选如下选项

运行项目

npm run serve

  • 运行结果

整理目录

删除src/assets中的所有logo.png

删除src/components中的所有文件

  • 修改src/route/index.js
import Vue from 'vue'
import VueRouter from 'vue-router'

Vue.use(VueRouter)

const routes = []

const router = new VueRouter({
  mode: 'history',
  base: process.env.BASE_URL,
  routes
})

export default router

删除src/views中所有文件

  • 修改src/app.vue
<template>
  <div id="app">
    初始化页面
  </div>
</template>

<style lang="scss">

</style>

  • 整理完目录如下

引入ElementUI

安装ElementUI

可以参考我之前的文章Vue2使用cli脚手架引入ElementUI

我直接全局安装了

npm i element-ui -S

引入ElementUI

  • 在 main.js 中写入以下内容:
import Vue from 'vue';
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';
import App from './App.vue';

Vue.use(ElementUI);

new Vue({
  el: '#app',
  render: h => h(App)
});

测试是否安装成功

  • 编写src/app.vue
<template>
  <div id="app">
    <el-button type="primary">测试</el-button>
  </div>
</template>

<script>

export default {
}
</script>

<style lang="scss">
</style>
  • 运行结果

编写路由搭架子

一级路由

  • 新建src/views/Login.vue
<template>
  <div>
    <h1>一级路由 Login</h1>
  </div>
</template>

<script>
export default {
  
}
</script>

<style>

</style>
  • 新建src/views/front/frontIndex.vue
<template>
  <div>
    <h1> 一级路由 前台</h1>
    <router-view></router-view>
  </div>
</template>

<script>
export default {

}
</script>

<style>

</style>
  • 新建src/views/admin/adminIndex.vue
<template>
  <div>
    <h1>一级路由 后台</h1>
    <router-view></router-view>
  </div>
</template>

<script>
export default {};
</script>

<style lang="scss" scope>
</style>

二级路由

  • 新建src/views/front/home.vue
<template>
  <div>
    <h2>二级路由Home</h2>
  </div>
</template>

<script>
export default {

}
</script>

<style>

</style>
  • 新建src/views/front/caricature.vue
<template>
  <div>
    <h2>二级路由漫画</h2>
  </div>
</template>

<script>
export default {

}
</script>

<style>

</style>
  • 新建src/views/admin/user.vue
<template>
  <div>
    <h2>二级路由 用户管理</h2>
  </div>
</template>

<script>
export default {

}
</script>

<style>

</style>
  • 新建src/views/admin/provider.vue
<template>
  <div>
      <h2>二级路由Provider</h2>
  </div>
</template>

<script>
export default {

}
</script>

<style>

</style>

修改src/router/index.js

import Vue from 'vue'
import VueRouter from 'vue-router'

Vue.use(VueRouter)

const routes = [
  // 重定向
  {path: '/', redirect: '/login'},
  {path: '/login', component: () => import('@/views/Login.vue')},
  {path: '/admin', component: () => import('@/views/admin/adminIndex.vue'),
    redirect: '/admin/user', // 重定向两种写法 推荐这种写法简单
    children:[
      {path: 'user', component: () => import('@/views/admin/user.vue')},
      {path: 'provider', component: () => import('@/views/admin/provider.vue')},
    ]
  },
  {path: '/front', component: () => import('@/views/front/frontIndex.vue'),
    children:[
      {path: '/front', redirect: '/front/home'},// 重定向两种写法
      {path: '/front/home', component: () => import('@/views/front/home.vue')},
      {path: '/front/caricature', component: () => import('@/views/front/caricature.vue')}
    ]
  }
]

const router = new VueRouter({
  mode: 'history',
  base: process.env.BASE_URL,
  routes
})

export default router
  • 运行结果

使用 ElementUI 中菜单组件

修改src/views/front/frontIndex.vue

<template>
  <div>
    <!-- <h1> 一级路由 前台</h1>
    <router-view></router-view> -->
    <el-container>
      <el-header>
        <!--
            router: 是否使用 vue-router 的模式,
            启用该模式会在激活导航时以 index 作为 path 进行路由跳转
          -->
          <!-- 
            这里 default-active 需要默认选中
            这里的default-active为什么不能写死呢?即 default-active="/front/home"
            因为路由是动态的,所以需要根据路由来动态设置
            如果写成上面的,那么路由切换的时候,菜单栏不会跟着切换。
            即出现  在http://localhost:8080/front/home页面已刷新,
                  默认选中变成了首页,但是还是展示漫画页面
          -->
          <!-- 
            mode: 模式,默认值 vertical(垂直展示) ,可选值 horizontal(水平展示)
          -->
          <!-- 
            background-color: 菜单栏背景色
            text-color: 菜单栏文字颜色
            active-text-color: 菜单栏激活的文字颜色
          -->
        <el-menu
          router
          :default-active="$route.path"
          class="el-menu-demo"
          mode="horizontal"
          background-color="#545c64"
          text-color="#fff"
          active-text-color="#ffd04b"
        >
          <el-menu-item index="/front/home">首页</el-menu-item>
          <el-menu-item index="/front/caricature">漫画</el-menu-item>
        </el-menu>
      </el-header>
      <el-main>
        <router-view></router-view>
      </el-main>
    </el-container>
  </div>
</template>

<script>
export default {};
</script>

<style lang="scss" scoped>
.el-header{
  margin: 0;
  padding: 0;
}
</style>

修改src/views/admin/adminIndex.vue

<template>
  <div>
    <!-- <h1>一级路由 后台</h1>
    <router-view></router-view> -->
    <el-container>
      <el-header class="el-header-admin"> 后台管理 </el-header>
      <el-container>
        <el-aside width="200px">
          <!--
            router: 是否使用 vue-router 的模式,
            启用该模式会在激活导航时以 index 作为 path 进行路由跳转
          -->
          <!-- 
            这里 default-active 需要默认选中
            这里的default-active为什么不能写死呢?即 default-active="/admin/user"
            因为路由是动态的,所以需要根据路由来动态设置
            如果写成上面的,那么路由切换的时候,菜单栏不会跟着切换。
            即出现  在http://localhost:8080/admin/provider页面已刷新,
                  默认选中变成了用户管理,但是还是展示供应商管理页面
          -->
          <!-- 
            mode: 模式,默认值 vertical(垂直展示) ,可选值 horizontal(水平展示)
          -->
          <!-- 
            background-color: 菜单栏背景色
            text-color: 菜单栏文字颜色
            active-text-color: 菜单栏激活的文字颜色
          -->
          <el-menu
            router
            :default-active="$route.path"
            class="el-menu-demo"
            mode="vertical"
            background-color="#545c64"
            text-color="#fff"
            active-text-color="#ffd04b"
          >
            <el-menu-item index="/admin/user">用户管理</el-menu-item>
            <el-menu-item index="/admin/provider">供应商管理</el-menu-item>
          </el-menu>
        </el-aside>
        <el-main>
          <router-view></router-view>
        </el-main>
      </el-container>
    </el-container>
    
  </div>
</template>

<script>
export default {};
</script>

<style lang="scss" scope>
* {
  margin: 0;
  padding: 0;
}
.el-header-admin {
  background-color: #545c64;
  font-size: 30px;
  color: #fff;
  line-height: 60px;
}
.el-menu-demo {
  height: 90vh;
}
</style>

运行结果

高级用法

ElementUI 的菜单组件(el-menu)默认的​​路由匹配行为是精确匹配​​,而非 router-link的模糊匹配(即包含匹配)。不过,可以通过自定义逻辑模拟类似效果。

以下是具体分析及实现方案:

1 ElementUI 菜单的默认路由机制​

路由跳转​​:

  • 在 el-menu上设置 :router="true"后
  • 点击 el-menu-item时会将其 index属性作为路径跳转(等价于 $router.push(index))。

​​激活状态匹配​​:

  • default-active属性需绑定当前路由路径(如 :default-active=“$route.path”)
  • 但​​仅支持精确匹配​​:只有当前路径与 index完全一致时,菜单项才会高亮。

2 与 router-link模糊匹配的区别​

特性​router-link(默认)ElementUI 菜单(默认)
匹配模式​​模糊匹配(路径包含即激活)精确匹配(路径完全一致才激活)
​​配置方式​​无需额外配置需手动绑定 default-active
​​子路径激活​​支持(如 /user激活 /user/list)❌ 不支持

3 实现模糊匹配的解决方案​

方案一:自定义计算属性动态匹配​

通过监听路由变化,手动检查当前路径是否包含菜单项的 index值:

<template>
  <el-menu :default-active="activeMenu">
    <el-menu-item index="/user" @click="$router.push('/user')">用户管理</el-menu-item>
  </el-menu>
</template>

<script>
export default {
  computed: {
    activeMenu() {
      const route = this.$route.path;
      // 模糊匹配逻辑:若当前路径包含菜单项的 index,则激活该菜单
      if (route.includes('/user')) return '/user';
      return route;
    }
  }
};
</script>

优点​​:灵活控制匹配规则,支持多级路径。

方案二:扩展 el-menu的 default-active逻辑​

封装高阶组件,重写 default-active的匹配逻辑:

Vue.component('fuzzy-menu', {
  props: ['menus'],
  computed: {
    activePath() {
      return this.menus.find(menu => 
        this.$route.path.includes(menu.index)
      )?.index;
    }
  },
  render(h) {
    return h('el-menu', {
      props: { defaultActive: this.activePath }
    }, this.menus.map(menu => 
      h('el-menu-item', { props: { index: menu.index } }, menu.label)
    ));
  }
});

适用场景​​:需多处复用模糊匹配菜单时。

方案三:递归处理嵌套菜单​

对于多级菜单(el-submenu),递归遍历子节点检查路径:

function findActiveMenu(menus, path) {
  for (const menu of menus) {
    if (path.includes(menu.index)) return menu.index;
    if (menu.children) {
      const childActive = findActiveMenu(menu.children, path);
      if (childActive) return childActive;
    }
  }
}

适用场景​​:动态生成复杂树形菜单时。

总结​​

​​默认行为​​:ElementUI 菜单仅支持精确路由匹配,无法直接实现 router-link的模糊匹配。

​​自定义方案​​:

  • 通过计算属性动态绑定 activeMenu✅
  • 封装高阶组件扩展匹配逻辑 ✅
  • 递归处理多级菜单路径 ✅

​​推荐场景​​:

  • 简单项目 → ​​方案一​​(计算属性)
  • 复杂系统 → ​​方案二/三​​(组件封装或递归)

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

相关文章

  • Vue在原窗口与新窗口打开外部链接的实现代码

    Vue在原窗口与新窗口打开外部链接的实现代码

    这篇文章主要介绍了Vue如何在原窗口与新窗口打开外部链接,文中给大家提到了vue跳转外部链接的实现代码,本文给大家介绍的非常详细,需要的朋友可以参考下
    2023-02-02
  • 讲解vue-router之什么是编程式路由

    讲解vue-router之什么是编程式路由

    编程式路由在我们的项目使用过程中最常用的的方法了。这篇文章主要介绍了讲解vue-router之什么是编程式路由,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-05-05
  • 详解Vue基于vue-quill-editor富文本编辑器使用心得

    详解Vue基于vue-quill-editor富文本编辑器使用心得

    这篇文章主要介绍了Vue基于vue-quill-editor富文本编辑器使用心得,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2019-01-01
  • vuex存值与取值的实例

    vuex存值与取值的实例

    今天小编大家分享一篇vuex存值与取值的实例,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2019-11-11
  • vue父子组件之间的传参的几种方式小结

    vue父子组件之间的传参的几种方式小结

    本文主要介绍了vue父子组件之间的传参的几种方式小结,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-04-04
  • Vue3实现转盘抽奖效果的示例详解

    Vue3实现转盘抽奖效果的示例详解

    这篇文章主要为大家详细介绍了如何通过Vue3实现简单的转盘抽奖效果,文中的示例代码讲解详细,具有一定的借鉴价值,感兴趣的可以了解一下
    2023-10-10
  • ant design的table组件实现全选功能以及自定义分页

    ant design的table组件实现全选功能以及自定义分页

    这篇文章主要介绍了ant design的table组件实现全选功能以及自定义分页,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-11-11
  • vue axios post发送复杂对象问题

    vue axios post发送复杂对象问题

    现在vue项目中,一般使用axios发送请求去后台拉取数据。这篇文章主要介绍了vue axios post发送复杂对象的一点思考,需要的朋友可以参考下
    2019-06-06
  • vue中v-text / v-html使用实例代码详解

    vue中v-text / v-html使用实例代码详解

    这篇文章主要介绍了vue中v-text / v-html使用实例代码详解,非常不错,代码简单易懂,具有一定的参考借鉴价值,需要的朋友可以参考下
    2019-04-04
  • vue实现城市列表选择功能

    vue实现城市列表选择功能

    这篇文章主要介绍了vue实现城市列表选择功能,本文通过实例代码给大家介绍的非常详细,具有一定的参考借鉴价值,需要的朋友可以参考下
    2018-07-07

最新评论