用el-menu自动生成无限级菜单 - 递归

简介: 用el-menu自动生成无限级菜单 - 递归

用el-menu自动生成无限级菜单 - 递归


简约菜单都可以使用el-menu生成,水平的菜单或者垂直的菜单。

本文是希望能帮助需求者更快熟悉el-menu的使用,以及传入菜单项能快速生成n级菜单。

基础介绍

使用的时候,最外层是el-menu,其上面属性,是用来配置整个菜单,如水平还是垂直、背景色、文字色、默认激活的菜单子项、默认展开的菜单子项等。

el-menu的子元素只有三种情况:

  • el-menu-item 就是普通的菜单项
  • el-submenu 是菜单项里还有子菜单
  • el-menu-item-group 是菜单项组,就是好几个菜单项有个标题


网络异常,图片无法展示
|

index的妙用

建议将每个el-menu-itemel-submenu上加上index的属性。

好处以下:

  • 选中的时候,有高亮的状态
  • 方便设置默认选中的菜单,可以default-active='anyIndex'
  • 方便设置默认展开的嵌套菜单,可以:default-openeds='["submenuIndex"]',这里必须是数组哈
  • 点击el-menu-item触发select事件,可以知道选了哪个和路径数组
  • 点击el-submenu触发open/close事件,可以知道选了哪个和路径数组
  • el-menu设置router属性的时候,index作为 path 进行路由跳转


网络异常,图片无法展示
|

折叠菜单

一级菜单每个加特定的图标,然后就可以折叠,这样最大化内容区。

折叠使用的是el-menucollapse属性。但记得将文字用标签裹起来,且加上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>


目录
相关文章
|
数据库
Layui入门&动态树&动态选项卡&用户增加&修改&删除&(一)
Layui入门&动态树&动态选项卡&用户增加&修改&删除&
|
4月前
|
开发框架 前端开发 JavaScript
使用DevExpress的GridControl实现多层级或无穷级的嵌套列表展示
使用DevExpress的GridControl实现多层级或无穷级的嵌套列表展示
|
4月前
el-input实现后缀图标和clearable的兼容,调整el-input clearable与自定义图标展示位置问题
el-input实现后缀图标和clearable的兼容,调整el-input clearable与自定义图标展示位置问题
174 1
|
4月前
|
前端开发 JavaScript
【定制需求】el-tree 树形控件实现:每级可单独选择,选择父级不选中子集,子集全部选中不自动选中父级,手写按钮可支持子集全选,以及取消子集全选,el-tree 树形控件取消父子级联动选择
【定制需求】el-tree 树形控件实现:每级可单独选择,选择父级不选中子集,子集全部选中不自动选中父级,手写按钮可支持子集全选,以及取消子集全选,el-tree 树形控件取消父子级联动选择
254 0
|
6月前
使用递归的方式删除菜单
使用递归的方式删除菜单
32 1
|
6月前
uniapp uni-combox 下拉提示无匹配项(完美解决--附加源码解决方案及思路)
uniapp uni-combox 下拉提示无匹配项(完美解决--附加源码解决方案及思路)
344 0
|
前端开发 JavaScript
饿了么UI中el-tree中的树节点选中高亮的两种常用方式(highlight-current属性)
饿了么UI中el-tree中的树节点选中高亮的两种常用方式(highlight-current属性)
438 0
|
6月前
el-cascader组件实现点击、递归勾选联动子集children所有选项被选中。
el-cascader组件实现点击、递归勾选联动子集children所有选项被选中。
Layui入门&动态树&动态选项卡&用户增加&修改&删除&(二)
Layui入门&动态树&动态选项卡&用户增加&修改&删除&
|
前端开发
el-tree菜单权限配置--是否要联动的问题
el-tree菜单权限配置--是否要联动的问题
148 1