背景

后台管理系统菜单权限的配置通常使用el-tree组件进行展示,而el-tree默认展示节点方式是纵向排版的,而UI设计的权限菜单排版有时可能是横向分布的,此时不仅需要自定义el-tree的节点,而且还用通过js操作el-tree的dom方式动态设定样式才能达到预期的UI效果。

实现el-tree横向排列

效果

先看看要实现菜单权限树横向排列的效果吧:
权限菜单

实现

  • 思路
    使用el-tree的render-content属性通过函数式的方式自定义树节点,当中通过操作el-tree的dom的方式动态改变el-tree的样式,动态添加元素达到预期的效果
  • 实现代码
    html代码
              <el-tree :data="menuTree" :props="defaultProps" default-expand-all :expand-on-click-node="false"
                       show-checkbox node-key="id" ref="menuTree" @check="getcheckNode"
                       :render-content="renderContent"
              >
              </el-tree>

js代码

      renderContent(h, { node, data, store }){
        console.log(node)
        node.isLeaf=true
        let classname=''
        if(node.level==2){
          classname='firstname'
        }
        if(node.level==4){
          classname='levelname'
        }
        if(node.level==3){
          classname='displayname'
        }
        if(this.isHasRadio(data)&&!this.isCheckBoxIdAryLoad&&this.getCheckedKeysArr.includes(data.id)){
          return (
            <p class={classname} style="display:flex;">
              {node.label}
              <div class="nodeCt">
                <div class="nodeRight">
                  <el-checkbox style="margin-left:10px;" on-change={(v)=>{this.checkChange(v,data)}} checked={this.isSelCheck(this.isHasRadio(data))}></el-checkbox>
                  <span>管理者</span>
                  <el-tooltip class="item" effect="dark" placement="top">
                    <div slot="content" style="width:120px;">
                      {this.isHasRadio(data).remark}
                    </div>
                    <i style="color:grey;" class="el-icon-question"></i>
                  </el-tooltip>
                </div>
              </div>
            </p>
          )
        }else{
          return (
            <p class={classname}>
              {node.label}
            </p>
          )
        }
      },
      changeCss() {
        let levelName = document.getElementsByClassName('levelname') // levelname是上面的最底层节点的名字
        let displayName=document.getElementsByClassName('displayname')
        let firstName=document.getElementsByClassName('firstname')
        for (let i = 0; i < levelName.length; i++) {
          // cssFloat 兼容 ie6-8  styleFloat 兼容ie9及标准浏览器
          levelName[i].parentNode.style.cssFloat = 'left' // 最底层的节点,包括多选框和名字都让他左浮动
          levelName[i].parentNode.style.paddingLeft='1px'
          levelName[i].parentNode.style.styleFloat = 'left'
          levelName[i].parentNode.parentNode.parentNode.style.display='flex'
        }
        for(let i=0;i<displayName.length;i++){
          displayName[i].parentNode.parentNode.style.display='flex'
          displayName[i].parentNode.insertAdjacentHTML('afterend', `<span style="color: #C8C8C8;padding-left:20px;">|</span>`)
        }
        for(let i=0;i<firstName.length;i++){
          if(firstName[i].parentNode.textContent!='首页'){
            firstName[i].parentNode.insertAdjacentHTML('afterend',`<div style="color: #C8C8C8;border:solid 1px #EFEFEF;margin-left:60px;margin-top: 5px;margin-bottom: 5px;"></div>`)
          }
          firstName[i].parentNode.parentNode.insertAdjacentHTML('afterend',`<div style="color: #C8C8C8;border:solid 1px #EFEFEF;margin-top: 5px;margin-bottom: 5px;"></div>`)
        }
      },
     showDialog(){
     setTimeout(this.changeCss(),500)
}
  • 代码解释
    (1)首先需要更改el-tree不同层级的节点布局,为不同层级设置不同的类名,然后操作dom节点动态设置flex布局改变el-tree为横向布局。
     let levelName = document.getElementsByClassName('levelname') // levelname是上面的最底层节点的名字
        let displayName=document.getElementsByClassName('displayname')
        let firstName=document.getElementsByClassName('firstname')
        for (let i = 0; i < levelName.length; i++) {
          // cssFloat 兼容 ie6-8  styleFloat 兼容ie9及标准浏览器
          levelName[i].parentNode.style.cssFloat = 'left' // 最底层的节点,包括多选框和名字都让他左浮动
          levelName[i].parentNode.style.paddingLeft='1px'
          levelName[i].parentNode.style.styleFloat = 'left'
          levelName[i].parentNode.parentNode.parentNode.style.display='flex'
        }
        for(let i=0;i<displayName.length;i++){
          displayName[i].parentNode.parentNode.style.display='flex'
          displayName[i].parentNode.insertAdjacentHTML('afterend', `<span style="color: #C8C8C8;padding-left:20px;">|</span>`)
        }

(2)为一级菜单和每个模块添加下划线同样操作dom动态的在这些元素后插入下划线元素。

     for(let i=0;i<displayName.length;i++){
          displayName[i].parentNode.parentNode.style.display='flex'
          displayName[i].parentNode.insertAdjacentHTML('afterend', `<span style="color: #C8C8C8;padding-left:20px;">|</span>`)
        }
        for(let i=0;i<firstName.length;i++){
          if(firstName[i].parentNode.textContent!='首页'){
            firstName[i].parentNode.insertAdjacentHTML('afterend',`<div style="color: #C8C8C8;border:solid 1px #EFEFEF;margin-left:60px;margin-top: 5px;margin-bottom: 5px;"></div>`)
          }
          firstName[i].parentNode.parentNode.insertAdjacentHTML('afterend',`<div style="color: #C8C8C8;border:solid 1px #EFEFEF;margin-top: 5px;margin-bottom: 5px;"></div>`)
        }

(3)注意自定义节点函数中return中返回的html代码需要条件做判断时需要写在return外层不能写在return内部即根据不同条件返回不容模板内容。

        if(this.isHasRadio(data)&&!this.isCheckBoxIdAryLoad&&this.getCheckedKeysArr.includes(data.id)){
          return (
            <p class={classname} style="display:flex;">
              {node.label}
              <div class="nodeCt">
                <div class="nodeRight">
                  <el-checkbox style="margin-left:10px;" on-change={(v)=>{this.checkChange(v,data)}} checked={this.isSelCheck(this.isHasRadio(data))}></el-checkbox>
                  <span>管理者</span>
                  <el-tooltip class="item" effect="dark" placement="top">
                    <div slot="content" style="width:120px;">
                      {this.isHasRadio(data).remark}
                    </div>
                    <i style="color:grey;" class="el-icon-question"></i>
                  </el-tooltip>
                </div>
              </div>
            </p>
          )
        }else{
          return (
            <p class={classname}>
              {node.label}
            </p>
          )
        }

(4)为防止样式不能更新到dom上建议设置延时器,指向样式变更相关操作。

     showDialog(){
     setTimeout(this.changeCss(),500)
}

(5)UI设计中没有el-tree的选择下拉按钮并且默认展开,处理设置el-tree默认展开,还要去除el-tree子节点的下拉箭头图标,只需在defaultProps中添加isLeaf属性,同时自定义节点将其设置为true即可。

data(){
return {
 defaultProps: {
          children: 'children',
          label: 'label',
          isLeaf: 'isLeaf'
        },
}
}
methods:{
  renderContent(h, { node, data, store }){
        console.log(node)
        node.isLeaf=true

}
}

参考资料

vue+element实现树状菜单并底层菜单横向排列

最后修改:2022 年 06 月 21 日
如果觉得我的文章对你有用,请随意赞赏