为了账号安全,请及时绑定邮箱和手机立即绑定

基于element-ui定义自己的Menu 菜单组件

标签:
Vue.js

在el-menu组件基础上扩展支持传递数据动态生成菜单项,使用方法与el-menu一样,增加了data 和 props 参数。

/**
   * 菜单组件
   * @module widgets/my-menu
   * @example
   *
   * // 使用说明
   */
  export default {
    name: 'MyMenu',
    /**
     * 属性参数
     * @property {Array} [data = []] data 构成菜单内容的数组
     * @property {Object} [props = { id: 'id', text: 'text', icon: 'icon', children: 'children', group: 'group', route: 'route' }] props 指引菜单组件根据data数组中元素的键名作为菜单中对应的显示内容。例如:数组内元素为 {g_id:1, str:'第一组'}, 可以通过设置"props={id: 'g_id', text: 'str'}"来将数组的g_id对应为id,str对应为text
     * @property {String} [mode = 'verticle'] mode 默认为垂直模式,横向 ‘horizontal’
     * @property {Boolean} [collapse = false] 是否水平折叠收起菜单(仅在 mode 为 vertical 时可用)
     * @property {String} [backgroundColor] backgroundColor='#FFFFFF' 菜单的背景色(仅支持 hex 格式)
     * @property {String} [textColor] 菜单的文字颜色(仅支持 hex 格式)
     * @property {String} [activeTextColor] 当前激活菜单的文字颜色(仅支持 hex 格式)
     * @property {String} [defaultActive] 当前激活菜单的 index。 defaultActive = '1'
     * @property {Array} [defaultOpeneds] 当前打开的sub-menu的 key 数组。 defaultOpeneds = ['2', '4']
     * @property {Boolean} [uniqueOpened = false] 是否只保持一个子菜单的展开
     * @property {String} [menuTrigger = 'click'] 子菜单打开的触发方式(只在 mode 为 horizontal 时有效)
     * @property {Boolean} [router = false] 是否使用 vue-router 的模式,启用该模式会在激活导航时以 index 作为 path 进行路由跳转
     */
    props: {
      // 菜单数据
      data: {
        type: Array,
        default() {
          return []
        }
      },
      // 数据字段名称映射
      props: {
        type: Object,
        default() {
          return {
            id: 'id',
            text: 'text',
            icon: 'icon',
            children: 'children',
            group: 'group',
            route: 'route'
          }
        }
      },
      // 模式 horizontal / vertical
      mode: String,
      // 是否水平折叠收起菜单(仅在 mode 为 vertical 时可用)
      collapse: Boolean,
      // 菜单的背景色(仅支持 hex 格式)
      backgroundColor: String,
      // 菜单的文字颜色(仅支持 hex 格式)
      textColor: String,
      // 当前激活菜单的文字颜色(仅支持 hex 格式)
      activeTextColor: String,
      // 当前激活菜单的 index
      defaultActive: String,
      // 当前打开的sub-menu的 key 数组
      defaultOpeneds: Array,
      // 是否只保持一个子菜单的展开
      uniqueOpened: Boolean,
      // 子菜单打开的触发方式(只在 mode 为 horizontal 时有效)
      menuTrigger: String,
      // 是否使用 vue-router 的模式,启用该模式会在激活导航时以 index 作为 path 进行路由跳转
      router: Boolean,
      // 弹出菜单的自定义类名
      popperClass: String
    },
    methods: {
      grouping(array) {
        let groups = {
          'default': []
        }
        let props = this.props
        array.forEach(n => {
          let key = n[props.group]
          if (key) {
            groups[key] = groups[key] || []
            groups[key].push(n)
          } else {
            groups['default'].push(n)
          }
        })
        return groups
      },
      createTitle(h, item) {
        return [
          h('i', {
            'class': item[this.props.icon]
          }),
          h('span', {
            slot: 'title'
          }, item[this.props.text])
        ]
      },
      createItem(h, item) {
        const key = (item[this.props.id] || '').toString()
        return h('el-menu-item', {
          props: {
            index: key,
            route: item[this.props.route]
          },
          key: key
        }, this.createTitle(h, item))
      },
      createSubmenu(h, item) {
        const key = (item[this.props.id] || '').toString()
        return h('el-submenu', {
          props: {
            index: (item[this.props.id] || '').toString(),
            popperClass: this.popperClass
          },
          key: key
        }, [h('template', {
          slot: 'title'
        }, this.createTitle(h, item)), this.createNodes(h, item[this.props.children])])
      },
      createGroup(h, title, items) {
        let nodes = []
        let props = this.props
        items.forEach(item => {
          if (item[props.children] && item[props.children].length > 0) {
            nodes.push(this.createSubmenu(h, item))
          } else {
            nodes.push(this.createItem(h, item))
          }
        })
        nodes.unshift(h('template', {
          slot: 'title'
        }, title))
        return h('el-menu-item-group', null, nodes)
      },
      createNodes(h, array) {
        let nodes = [], groups = this.grouping(array)
        let props = this.props
        for (let key in groups) {
          let items = groups[key] || []
          if (key === 'default') {
            items.forEach(item => {
              if (item[props.children] && item[props.children].length > 0) {
                nodes.push(this.createSubmenu(h, item))
              } else {
                nodes.push(this.createItem(h, item))
              }
            })
          } else {
            nodes.push(this.createGroup(h, key, items))
          }
        }
        return nodes
      },
      open(index) {
        this.$refs.menu.open(index)
      },
      close(index) {
        this.$refs.menu.close(index)
      }
    },
    render(h) {
      return h('el-menu', {
        props: {
          ...this.$props
        },
        'class': 'my-menu',
        on: {
          /**
           * 触发选中事件
           * @event select
           * @param index {String} 选中列表id
           * @param indexPath {Array} 选中列表对应的路径 如:['item1', 'item1-1']
           */
          select: (index, indexPath) => this.$emit('select', index, indexPath),
          /**
           * 触发列表组(子菜单)展开事件
           * @event open
           * @param index {String} 选中列表id
           * @param indexPath {Array} 选中列表对应的路径 如:['item1', 'item1-1']
           */
          open: (index, indexPath) => this.$emit('open', index, indexPath),
          /**
           * 触发列表组(子菜单)收起事件
           * @event close
           * @param index {String} 选中列表id
           * @param indexPath {Array} 选中列表对应的路径 如:['item1', 'item1-1']
           */
          close: (index, indexPath) => this.$emit('close', index, indexPath)
        },
        ref: 'menu'
      }, this.createNodes(h, this.data))
    }
  }

图片描述
代码如下:

<template>
<my-menu :data="menus" mode="horizontal"></my-menu>
</template>
<script>
export default {
data() {
  return {
    menus: [{
      id: 1,
      text:'处理中心',
      icon: 'el-icon-goods'
    },{
      id: 2,
      text:'我的工作台',
      icon: 'el-icon-setting',
      children: [{
        id: 21,
        text: '选项一'
      }, {
        id: 22,
        text: '选项二'
      }, {
         id: 23,
         text: '选项三'
       }]
    }, {
      id: 3,
      text: '消息中心',
      icon: 'el-icon-phone'
    }, {
      id: 4,
      text: '订单管理',
      icon: 'el-icon-news'
    }]
  }
}
}
</script>

图片描述
代码如下:

<template>

<div style="width: 250px">
 <my-menu :data="menus"></my-menu>
</div>
</template>
<script>
export default {
data() {
  return {
    menus: [{
      id: 1,
      text:'处理中心',
      icon: 'el-icon-goods'
    },{
      id: 2,
      text:'我的工作台',
      icon: 'el-icon-setting',
      children: [{
        id: 21,
        text: '选项一'
      }, {
        id: 22,
        text: '选项二'
      }, {
         id: 23,
         text: '选项三'
       }]
    }, {
      id: 3,
      text: '消息中心',
      icon: 'el-icon-phone'
    }, {
      id: 4,
      text: '订单管理',
      icon: 'el-icon-news'
    }]
  }
}
}
</script>
点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消