用el-menu自动生成无限级菜单 - 递归
简约菜单都可以使用el-menu
生成,水平的菜单或者垂直的菜单。
本文是希望能帮助需求者更快熟悉el-menu
的使用,以及传入菜单项能快速生成n级菜单。
基础介绍
使用的时候,最外层是el-menu
,其上面属性,是用来配置整个菜单,如水平还是垂直、背景色、文字色、默认激活的菜单子项、默认展开的菜单子项等。
el-menu
的子元素只有三种情况:
- el-menu-item 就是普通的菜单项
- el-submenu 是菜单项里还有子菜单
- el-menu-item-group 是菜单项组,就是好几个菜单项有个标题
网络异常,图片无法展示
|
index的妙用
建议将每个el-menu-item
和el-submenu
上加上index
的属性。
好处以下:
- 选中的时候,有高亮的状态
- 方便设置默认选中的菜单,可以
default-active='anyIndex'
- 方便设置默认展开的嵌套菜单,可以
:default-openeds='["submenuIndex"]'
,这里必须是数组哈 - 点击
el-menu-item
触发select事件,可以知道选了哪个和路径数组 - 点击
el-submenu
触发open/close事件,可以知道选了哪个和路径数组 el-menu
设置router
属性的时候,index作为 path 进行路由跳转
网络异常,图片无法展示
|
折叠菜单
一级菜单每个加特定的图标,然后就可以折叠,这样最大化内容区。
折叠使用的是el-menu
的collapse
属性。但记得将文字用标签裹起来,且加上slot='title'
,这样框架本身将title
会隐藏起来,且在hover
的时候显示出来。
网络异常,图片无法展示
|
网络异常,图片无法展示
|
重点来了:生成菜单
先简单点,只有二级菜单。 data增加menus,然后将模板部分,该循环循环,该判断判断,常量的地方变成变量。
网络异常,图片无法展示
|
生成n级菜单,肯定递归哈
如果没有写过递归组件的,可以尝试先写下三级菜单。
然后将重复的地方,提出来作为一个组件就可以了。
递归组件,需要多思考,多敲哈~
网络异常,图片无法展示
|
提取出来的MiddleMenu
如下:
网络异常,图片无法展示
|
抽离出菜单组件,传入菜单项配置自动生成菜单
这里就是把data
里的menus
变成传参,然后将el-menu
再包装一层,巧妙的用下$attrs
和$listeners
。
网络异常,图片无法展示
|
使用的时候
create-menu(:menus='menus' default-active='xx' style='width:210px' @select='handleSelect')
水平菜单和其他属性
如果觉得还需要什么功能,优先去官网看看。
- 想要水平菜单:
mode='horizontal'
- 想设置菜单的背景色、文字色、激活菜单的文字色(夜间模式):
background-color="#545c64" text-color="#fff" active-text-color="#ffd04b"
- 只想有一个子菜单展开:
unique-opened
- 打开子菜单的方式可以设置hover:
menu-trigger='hover'
- 不要折叠的动画效果:
:collapse-transition='false'
- 点击菜单项直接去相应的路由:
router
,且相应的index设置成路由路径
附注代码
最近试着手写实现el-menu组件,有兴趣可以看下
基础介绍代码
section(style='width:210px') el-menu el-menu-item 单项菜单1 el-menu-item 单项菜单2 el-submenu template(slot='title') 有子菜单,带展开小箭头 el-menu-item 子菜单1 el-menu-item 子菜单2 el-menu-item-group(title='菜单组,直接展开') el-menu-item 组员1 el-menu-item 组员2
加index代码
<template lang='pug'> section(style='width:210px') el-menu(default-active='menu1' :default-openeds='["submenu1"]' @open='handleOpen' @close='handleClose' @select='handleSelect') el-menu-item(index='menu1') 单项菜单1 el-menu-item(index='menu2') 单项菜单2 el-submenu(index='submenu1') template(slot='title') 有子菜单,带展开小箭头 el-menu-item(index='menu1-1') 子菜单1 el-menu-item(index='menu1-2') 子菜单2 el-menu-item-group(title='菜单组,直接展开') el-menu-item(index='menu3') 组员1 el-menu-item(index='menu4') 组员2 </template> <script> export default { methods: { handleOpen (key, keyPath) { console.log('open事件', key, keyPath) }, handleClose (key, keyPath) { console.log('close事件', key, keyPath) }, handleSelect (key, keyPath) { console.log('select事件', key, keyPath) } } } </script>
折叠菜单代码
<template lang='pug'> section(style='width:210px') el-menu.el-menu-vertical-demo(default-active='menu1' :collapse='isCollapse') el-menu-item(index='menu1') i.el-icon-location span(slot='title') 单项菜单1 el-menu-item(index='menu2') i.el-icon-document span(slot='title') 单项菜单2 el-submenu(index='submenu1') template(slot='title') i.el-icon-setting span(slot='title') 有子菜单 el-menu-item(index='menu1-1') 子菜单1 el-menu-item(index='menu1-2') 子菜单2 div(style='margin-top:20px') el-button(@click='isCollapse=!isCollapse') {{isCollapse?'展开':'折叠'}} </template> <script> export default { data () { return { isCollapse: true } } } </script>
生成菜单,只有二级代码
<template lang='pug'> section(style='width:210px') el-menu.el-menu-vertical-demo(default-active='首页' :collapse='isCollapse') template(v-for='(item,outerIndex) in menus' ) el-submenu(v-if='item.children' :index='item.text' :key='outerIndex') template(slot='title') i(:class='item.iconClass') span(slot='title') {{item.text}} el-menu-item(v-for='(innerItem,innerIndex) in item.children' :key='innerIndex' :index='innerItem.text') {{innerItem.text}} el-menu-item(v-else :index='item.text' :key='outerIndex') i(:class='item.iconClass') span(slot='title') {{item.text}} div(style='margin-top:20px') el-button(@click='isCollapse=!isCollapse') {{isCollapse?'展开':'折叠'}} </template> <script> export default { data () { let menus = [ { text: '首页', iconClass: 'el-icon-document' }, { text: '人员管理', iconClass: 'el-icon-user', children: [ { text: '教师管理' }, { text: '助教管理' } ] }, { text: '权限管理', iconClass: 'el-icon-setting', children: [ { text: '角色管理' }, { text: '人员角色' } ] } ] return { isCollapse: false, menus } } } </script>
生成n级菜单代码
<!-- MiddleMenu.vue --> <template lang="pug"> //- 这里注意不能使用div包裹,因为menu的标签很多是li,不能使用别的标签,所以使用component component(:is='menuItem.children?"el-submenu":"el-menu-item"' :index='menuItem.text') template(v-if='menuItem.children') template(slot='title') i(:class='menuItem.iconClass') span(slot='title') {{menuItem.text}} //- 和Index重复的地方,这也是递归的关键 template(v-for='(innerItem,innerIndex) in menuItem.children') middle-menu(:menu-item='innerItem' :key='innerIndex') template(v-else) i(:class='menuItem.iconClass') span(slot='title') {{menuItem.text}} </template> <script> export default { name: 'middle-menu', props: { menuItem: { type: Object, required: true } } } </script>
<!-- Index.vue --> <template lang='pug'> section(style='width:210px') el-menu.el-menu-vertical-demo(default-active='首页' :collapse='isCollapse') //- 和MiddleMenu重复的地方 template(v-for='(item,outerIndex) in menus' ) middle-menu( :menu-item='item' :key='outerIndex') div(style='margin-top:20px') el-button(@click='isCollapse=!isCollapse') {{isCollapse?'展开':'折叠'}} </template> <script> import MiddleMenu from './components/MiddleMenu' export default { components: { MiddleMenu }, data () { let menus = [ { text: '首页', iconClass: 'el-icon-document' }, { text: '人员管理', iconClass: 'el-icon-user', children: [ { text: '教师管理', children: [{ text: '数学系' }] }, { text: '助教管理' } ] }, { text: '权限管理', iconClass: 'el-icon-setting', children: [ { text: '角色管理' }, { text: '人员角色' } ] } ] return { isCollapse: false, menus } } } </script>
抽离出来的菜单组件
<!-- CreateMenu.vue --> <template lang='pug'> el-menu(v-bind='$attrs' v-on='$listeners') template(v-for='(item,outerIndex) in menus' ) middle-menu(:menu-item='item' :key='outerIndex') </template> <script> import MiddleMenu from './MiddleMenu' export default { components: { MiddleMenu }, props: { menus: { type: Array, required: true } } } </script>