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