ElementUI之菜单(Menu)使用
文章目录
- 项目创建
- 创建项目
- 运行项目
- 整理目录
- 删除src/assets中的所有logo.png
- 删除src/components中的所有文件
- 修改src/route/index.js
- 删除src/views中所有文件
- 修改src/app.vue
- 整理完目录如下
- 引入ElementUI
- 安装ElementUI
- 引入ElementUI
- 测试是否安装成功
- 编写src/app.vue
- 运行结果
- 编写路由搭架子
- 一级路由
- 新建src/views/Login.vue
- 新建src/views/front/frontIndex.vue
- 新建src/views/admin/adminIndex.vue
- 二级路由
- 新建src/views/front/home.vue
- 新建src/views/front/caricature.vue
- 新建src/views/admin/user.vue
- 新建src/views/admin/provider.vue
- 修改src/router/index.js
- 修改app.vue
- 运行结果
- 使用 ElementUI 中菜单组件
- 修改src/views/front/frontIndex.vue
- 修改src/views/admin/adminIndex.vue
- 运行结果
- 高级用法
- 1 ElementUI 菜单的默认路由机制
- 2 与 router-link模糊匹配的区别
- 3. 实现模糊匹配的解决方案
- 方案一:自定义计算属性动态匹配
- 方案二:扩展 el-menu的 default-active逻辑
- 方案三:递归处理嵌套菜单
- 4 总结
项目创建
创建项目
我的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
修改app.vue
<template><div id="app"><router-view></router-view></div>
</template><script>export default {}
</script><style lang="scss"></style>
运行结果
使用 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-menurouter: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-menurouter: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;}}
}
适用场景:动态生成复杂树形菜单时。
4 总结
-
默认行为:ElementUI 菜单仅支持精确路由匹配,无法直接实现 router-link的模糊匹配。
-
自定义方案:
-
通过计算属性动态绑定 activeMenu✅
-
封装高阶组件扩展匹配逻辑 ✅
-
递归处理多级菜单路径 ✅
-
-
推荐场景:
-
简单项目 → 方案一(计算属性)
-
复杂系统 → 方案二/三(组件封装或递归)
-