动态渲染 Element UI el-menu 组件

本文分享了在ElementUI中使用el-menu组件实现水平和垂直模式动态渲染的方法,包括自定义组件代码和使用示例,解决了收缩模式下显示异常的问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

相信大家在使用 Element UIel-menu 组件的时候,都碰到过如何通过数据动态渲染的问题,而官方的文档却没有这个实例,网上找的一些博客大部分人都实现了 el-menu 的垂直模式,而水平模式却没有,并且垂直模式的 el-menu 在收缩的时候会出现问题,但是他们并没有去解决,让我很苦恼,没办法,只能自己去解决了,先给大家看看效果先:
效果图

如上所示,水平和垂直模式的el-menu都一实现,而且垂直的el-menu收缩也正常,下面给大家贴上代码:

水平 el-menu

水平模式的el-menu主要分为两个js文件:

  1. ch-horizonal-menu.js
  2. ch-horizonal-menu-item.js
ch-horizonal-menu.js
;(function (root , factory) {
    if(typeof exports === 'object') {
        module.exports = exports = factory();
    } else if(typeof define === 'function' && define.amd) {
        define([] , factory());
    } else {
        root.chHorizonalMenu = factory();
    }
})(this , function () {
    let chHorizonalMenu = {
        template:
        '<ul class="ch-horizonal-menu" :style="{backgroundColor:backgroundColor}">'+
            '<ch-horizonal-menu-item '+
                ':menus="data" '+
                ':active-text-color="activeTextColor"'+
                ':background-color="backgroundColor"'+
                ':activeId="activeId"'+
                '@item-click="itemClick">'+
            '</ch-horizonal-menu-item>'+
        '</ul>'
        ,
        props:{
            data:{
                type:Array , 
                default:function () {
                    return []
                }
            },
            backgroundColor:{
                type:String,
                default:'rgb(46, 50, 61)'
            },
            activeTextColor:{
                type:String,
                default:'rgb(255, 208, 75)'
            }
        },
        data:function () {
            return {
                activeId:null,
                submenuIds:[]
            }
        },
        methods:{
            itemClick:function (params) {
                this.activeId = params.id;
                this.removeActive();
                this.$emit('item-click' , params);
            },
            removeActive:function () {
                var _this = this ;
                var activeNodes = this.$el.getElementsByClassName('is_active');
                [].slice.call(activeNodes).forEach(function (el) {
                    el.className = el.className.replace(/ is_active/ , '');
                    el.style.color = '#fff';
                })
            }
        }
    }
    return {
        name:'ch-horizonal-menu',
        template:chHorizonalMenu
    }
})

ch-horizonal-menu-item.js
;(function (root , factory) {
    if(typeof exports === 'object') {
        module.exports = exports = factory();
    } else if(typeof define === 'function' && define.amd) {
        define([] , factory());
    } else {
        root.chHorizonalMenuItem = factory();
    }
})(this , function () {
    let chHorizonalMenuItem = {
        template:
        '<div>'+
            '<template v-for = "menu in menus">'+
                '<li v-if="menu.children && menu.children.length" '+
                    '@mouseenter="onMouseEnter($event , menu.id)"'+
                    '@mouseleave="onMouseLeave($event)"'+
                    'class="ch-horizonal-menu-item ch-horizonal-submenu">'+
                    '<div class="ch-horizonal-submenu__title">'+
                        '<span>{{menu.name}}</span>'+
                        '<i :class=\'[ floor == 1 ? "el-icon-arrow-down" : "el-icon-arrow-right", "ch-horizonal-submenu__icon-arrow"]\'></i>'+
                    '</div>'+
                    '<div class="ch-horizonal-submenu_inner" v-show="current_id == menu.id">'+
                        '<ul class="ch-horizonal-menu__inner" '+
                            ':style="{backgroundColor:backgroundColor}">'+
                            '<ch-horizonal-menu-item '+
                                ':menus="menu.children" '+
                                ':active-text-color="activeTextColor"'+
                                ':background-color="backgroundColor"'+
                                ':activeId="activeId"'+
                                ':level="floor" '+
                                '@item-click="itemClick">'+
                            '</ch-horizonal-menu-item>'+
                        '</ul>'+
                    '</div>'+
                '</li>'+
                '<li v-else '+
                    ':style="{color:activeId == menu.id ? activeTextColor :\'#fff\' }"'+
                    'class="ch-horizonal-menu-item"'+
                    '@click="itemClick(menu , $event)">{{menu.name}}</li>'+
            '</template>'+
        '</div>'
        ,
        props:{
            menus:{
                type: Array,
                default: function () {
                    return [];
                }
            },
            level:{
                type: Number,
                default:0
            },
            activeId:{
                type:[Number , String],
                default:''
            },
            activeTextColor:String,
            backgroundColor:String
        },
        data:function () {
            return {
                show:false,
                floor:this.level,
                timeId:0,
                current_id:-1,
                isActive:false
            }
        },
        created:function () {
            this.floor++;
        },
        methods:{
            onMouseEnter:function (event , id) {
                clearTimeout(this.timeId);
                this.current_id = id ;
                this.$nextTick(function () {
                    if(this.floor > 1) {
                        var innerMenu = event.target.querySelector('.ch-horizonal-menu__inner');
                        var innerMenuItem = event.target.querySelector('.ch-horizonal-menu-item');
                        innerMenu.style.left = (innerMenuItem.offsetWidth - 20 + 5) + 'px';
                        innerMenu.style.top  = (-innerMenuItem.offsetHeight) + 'px';
                    }
                })
            },
            onMouseLeave:function (event) {
                this.timeId = setTimeout(function () {
                    this.current_id = -1 ;
                }.bind(this) , 200)
            },
            itemClick:function (menu , event) {
                this.current_id = -1 ;
                this.$emit('item-click' , menu);
                if(event) this.setParentNodeActive(event.target.parentNode , 'ch-horizonal-submenu');
            },
            setParentNodeActive:function (el , cls) {
                var classList = el.className.split(' ');
                if(classList.indexOf('ch-horizonal-menu') == -1) {
                    if(classList.indexOf(cls) != -1) {
                        el.style.color = this.activeTextColor;
                        el.className = el.className.concat(' is_active');
                    }
                    this.setParentNodeActive(el.parentNode , cls);
                }
            }
        }
    }
    return {
        name:'ch-horizonal-menu-item',
        template:chHorizonalMenuItem
    }
})

使用示例

   // 注册 chHorizonalMenuItem 必须在 chHorizonalMenu 前注册
   Vue.component(chHorizonalMenuItem.name , chHorizonalMenuItem.template);
   Vue.component(chHorizonalMenu.name , chHorizonalMenu.template);
  
  <ch-horizonal-menu 
     :data="menus"
      background-color="#1B75D5"
      @item-click="onHorizonalMenuClick">
  </ch-horizonal-menu>

垂直 el-menu

ch-vertical-menu-item.js
;(function (root , factory) {
    if(typeof exports === 'object') {
        module.exports = exports = factory();
    } else if(typeof define === 'function' && define.amd) {
        define([] , factory());
    } else {
        root.chVerticalMenuItem = factory();
    }
})(this , function () {
    var chVerticalMenuItem = {
        template:
        '<div class="ch-menu-wrapper">'+
            '<template v-for="menu in data">'+

                '<el-menu-item v-if="!menu.children" :index="menu.id" @click="handleMenuItem(menu)"> '+
                    '<i v-if="menu.icon" :class="menu.icon"></i>'+
                    '<span slot="title">{{menu.name}}</span>'+
                '</el-menu-item>'+
            
                '<el-submenu v-else :index="menu.id">'+
                    '<template slot="title">'+
                        '<i v-if="menu.icon" :class="menu.icon"></i>'+
                        '<span>{{menu.name}}</span>'+
                    '</template>'+
                    '<ch-vertical-menu-item :data="menu.children" @item-click="onMenuClick"></ch-vertical-menu-item>'+
                '</el-submenu>'+
            '</template>'+
        '</div> ',
        props:{
            data:{
                type:Array,
                default:function () {
                    return [] ;
                }
            }
        },
        methods:{
            handleMenuItem:function (menu) { 
                this.$emit("item-click" , menu);
            },
            onMenuClick:function (menu) {
                this.$emit("item-click" , menu);
            }
        }
    }
    return {
        name:'ch-vertical-menu-item',
        template:chVerticalMenuItem
    }
})
使用示例
 // 注册
 Vue.component(chVerticalMenuItem.name , chVerticalMenuItem.template);
 
 <el-menu
     :default-active="activeMenuId"
      :background-color="themeColor"
      text-color="#fff"
      :collapse="isCollapse"
      class="el-menu-vertical-left"
      active-text-color="#ffd04b">
      	<ch-vertical-menu-item :data="menus" @item-click="onCHMenuClick"></ch-vertical-menu-item>
 </el-menu>

由于垂直模式的 el-menu 只是用 Element UI原生组件进行再封装,所以相关配置请参考其文档,而水平模式的 el-menu 则是自定义的组件,因此两者没有封装到一起,用法上也有所不同,还请各位见谅!

完整代码请查看 vue-web-frame 导航菜单示例

<think>我们正在处理关于调整ElementUIel-menu组件高度的问题。根据用户提供的引用内容,我们可以从两个方面来考虑:垂直模式和水平模式。引用[1]提到:垂直模式的el-menu是使用ElementUI原生组件进行再封装,所以配置参考官方文档;水平模式的el-menu是自定义组件,用法不同。引用[2]则给出了一个水平菜单高度调整的示例:通过外部包裹div,并使用CSS选择器来设置菜单项的高度和行高。根据用户的问题“我想修改el-menu组件的高度样式”,我们需要区分两种情况:垂直菜单和水平菜单。对于垂直菜单(vertical):通常,垂直菜单的高度会随着菜单项的多少自动调整。如果我们希望固定高度或者调整高度,可以通过设置外层容器的高度来实现,然后让菜单高度100%适应容器。对于水平菜单(horizontal):引用[2]中的示例展示了如何调整水平菜单的高度。通过CSS选择器设置`.el-menu-item`和`.el-submenu__title`的高度和行高。具体步骤:1.垂直菜单高度调整:我们可以将el-menu包裹在一个div中,设置这个div的高度,然后让el-menu的高度设置为100%来填充容器。例如:```html<divstyle="height:500px;"><!--设置一个固定高度--><el-menumode="vertical"style="height:100%">...菜单项...</el-menu></div>```或者通过CSS类:```css.menu-container{height:500px;}.menu-container.el-menu{height:100%;}```2.水平菜单高度调整:根据引用[2],我们需要覆盖ElementUI的默认样式。注意,因为水平菜单项是行内元素,所以直接设置菜单项(.el-menu-item)和子菜单标题(.el-submenu__title)的高度和行高。示例CSS:```css/*设置水平菜单的菜单项高度*/.custom-horizontal-menu.el-menu--horizontal>.el-menu-item{height:60px;/*设置高度*/line-height:60px;/*设置行高,保证文字垂直居中*/}/*设置水平菜单的子菜单标题高度*/.custom-horizontal-menu.el-menu--horizontal>.el-submenu.el-submenu__title{height:60px;line-height:60px;}```然后在el-menu组件上添加自定义类名`custom-horizontal-menu`(或者使用其他选择器):```html<el-menuclass="custom-horizontal-menu"mode="horizontal">...菜单项...</el-menu>```注意:由于ElementUI的样式可能受到作用域的影响(例如在scoped的style中),如果发现样式不生效,可能需要使用深度选择器(如::v-deep、/deep/或>>>,取决于构建工具)。例如,在Vue单文件组件中,如果使用了scoped,可以这样写:```css<stylescoped>/*深度选择器*/.menu-container::v-deep.el-menu--horizontal>.el-menu-item{height:60px;line-height:60px;}/*或者使用其他深度选择器语法,根据环境支持情况*/</style>```另外,如果用户使用的是垂直菜单,但希望调整每个菜单项的高度,可以通过设置每个菜单项的高度样式来实现,例如:```css.el-menu-item{height:50px;line-height:50px;}```总结:调整高度的方法取决于菜单的模式(垂直或水平)以及具体的需求。通过外层容器控制垂直菜单的整体高度,通过覆盖ElementUI的默认样式来调整水平菜单项的高度。最后,请注意,由于ElementUI版本更新,类名可能会有变化,建议用户根据实际DOM结构进行调整。相关问题:1.如何调整ElementUIel-menu组件的背景颜色?2.el-menu组件在垂直模式下如何实现滚动条?3.如何动态改变el-menu的菜单项高度?</think>### 调整 Element UI el-menu 组件高度的方法 调整 `el-menu` 高度需要根据**菜单模式**采用不同的方法,以下是具体解决方案: #### 1. **水平菜单 (mode="horizontal")** ```css /* 设置菜单项高度 */ .el-menu--horizontal > .el-menu-item { height: 60px !important; /* 自定义高度 */ line-height: 60px !important; } /* 设置包含子菜单的标题高度 */ .el-menu--horizontal > .el-submenu > .el-submenu__title { height: 60px !important; line-height: 60px !important; } ``` #### 2. **垂直菜单 (mode="vertical")** ```html <div class="menu-wrapper" style="height: 500px;"> <!-- 外层容器控制高度 --> <el-menu class="custom-vertical-menu" background-color="#545c64" text-color="#fff" active-text-color="#ffd04b" mode="vertical" > <!-- 菜单内容 --> </el-menu> </div> ``` ```css .menu-wrapper .custom-vertical-menu { height: 100% !important; /* 继承外层高度 */ } ``` #### 3. **通用注意事项** - **样式穿透**:在 Vue scoped 样式中使用深度选择器: ```css /* Vue2 语法 */ >>> .el-menu-item { height: 50px; } /* Vue3 语法 */ :deep(.el-submenu__title) { line-height: 70px; } ``` - **动态高度**:结合 `:style` 绑定实现响应式高度: ```html <el-menu :style="{ height: menuHeight + 'px' }"> ``` ```js data() { return { menuHeight: window.innerHeight * 0.8 } } ``` > **关键区别**:水平模式需直接修改菜单项样式,垂直模式通过外层容器控制整体高度[^1][^2]。 --- ### 相关问题 1. 如何修改 Element UI 菜单的激活项背景色? 2. 在 el-menu 中如何实现响应式高度调整? 3. 如何解决 el-menu 折叠后子菜单图标错位问题? 4. 垂直菜单出现滚动条时如何优化样式? [^1]: 动态渲染 Element UI el-menu 组件。由于垂直模式的 el-menu 只是用 Element UI原生组件进行再封装,所以相关配置请参考其文档,而水平模式的 el-menu 则是自定义的组件,因此两者没有封装到一起,用法上也有所不同。 [^2]: vue vue-element-ui组件 el-menu高度设置。外面包个div,再设置属性。
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值