ElementUI之菜单(Menu)的使用方式
作者: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✅
- 封装高阶组件扩展匹配逻辑 ✅
- 递归处理多级菜单路径 ✅
推荐场景:
- 简单项目 → 方案一(计算属性)
- 复杂系统 → 方案二/三(组件封装或递归)
以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。
