动态渲染 Element UI el-menu 组件

相信大家在使用 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 导航菜单示例

  • 7
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
您好!对于动态侧边栏,您可以使用 Element UI 中的 el-menu 组件来实现。el-menu 是一个强大的菜单组件,可以根据数据动态生成菜单项。 首先,您需要准备好菜单的数据。可以是一个数组,每个元素代表一个菜单项,包含菜单的标题、图标、路径等信息。 然后,在页面中使用 el-menu 组件,并通过 v-for 指令循环渲染菜单项。使用 v-bind 指令将菜单项的数据绑定到组件的属性上,例如 title、icon、index 等。 示例代码如下所示: ```html <el-menu :default-active="$route.path" class="el-menu-vertical-demo" @open="handleOpen" @close="handleClose" router> <template v-for="item in menuList"> <el-submenu v-if="item.children && item.children.length > 0" :key="item.index" :index="item.index"> <template slot="title"> <i :class="item.icon"></i> <span>{{ item.title }}</span> </template> <el-menu-item v-for="child in item.children" :key="child.index" :index="child.index"> <router-link :to="child.path">{{ child.title }}</router-link> </el-menu-item> </el-submenu> <el-menu-item v-else :key="item.index" :index="item.index"> <i :class="item.icon"></i> <span>{{ item.title }}</span> </el-menu-item> </template> </el-menu> ``` 在上面的示例中,menuList 是一个数组,保存了菜单项的信息。使用 v-for 指令将其循环渲染成菜单项。如果菜单项有子菜单,则使用 el-submenu 组件包裹 el-menu-item 组件。如果没有子菜单,则直接使用 el-menu-item 组件。 通过 :index 绑定菜单项的索引值,可以实现高亮当前选中的菜单项。使用 :default-active 绑定 $route.path,可以根据当前路由路径自动选中对应的菜单项。 以上就是使用 el-menu 实现动态侧边栏的基本步骤,您可以根据自己的需求进行进一步的定制和样式调整。希望能对您有帮助!如果还有其他问题,请随时提问。
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值