后台项目-element-plus递归生成sidebar总结

前言

后台项目需要根据router生成sidebar,本来以为使用element-plus不会遇到什么问题,但是动手做还是有很多bug,小小记录一下

根据路由生成sidebar

index.vue部分的代码很简单,配置一下el-menu的属性,然后把routes传给sidebar-item。这里的传给sidebar-item的数据都是有用的。

      <el-menu :collapse="isCollapse"
               :unique-opened="false"
               :collapse-transition="false"
               mode="vertical">
        <sidebar-item v-for="route in routes"
                      :key="route.path"
                      :item="route"
                      :base-path="route.path" />
      </el-menu>
复制代码

sidebar-item部分的代码稍微有点复杂。首先我们先思考传给sidebar-item的路由共有哪几种。

  • 无子路由的普通路由
  • 有一个子路由的嵌套路由
  • 有多个子路由的嵌套路由

但是其实不止这三种,当传入路由无子路由时你需要额外一个变量is-nest去判断它是否已经是一个子路由,所以还有一种。

  • 无子路由的嵌套路由

我们把有一个子路由的嵌套路由与无子路由的普通路由合并,就有下面的生成代码

<div v-if="!item.hidden">
    <template v-if='onlyHasOneShowing(item)&&(!onlyOneChild.date.children||onlyOneChild.date.noShowChild)'>
      <component :is="isHttp(item.path)"
                 v-bind="propsLink(pathResolve(onlyOneChild.date.path))">
        <el-menu-item :index='pathResolve(onlyOneChild.date.path)'
                      :class="{'submenu-title-noDropdown':!isNest}">
          <item :icon="onlyOneChild.date.meta.icon"
                :title="onlyOneChild.date.meta.title" />
        </el-menu-item>
      </component>

    </template>
    <el-sub-menu v-else
                 :index="pathResolve(item.path)"
                 popper-append-to-body>
      <template #title>
        <item v-if="item.meta"
              :icon="item.meta && item.meta.icon"
              :title="item.meta.title" />
      </template>
      <sidebar-item v-for="child in item.children"
                    :key="child.path"
                    :is-nest="true"
                    :item="child"
                    :base-path="pathResolve(child.path)"
                    class="nest-menu" />
    </el-sub-menu>
</div>
复制代码

修复因为递归生成菜单导致el-menu无法折叠的问题

如果问我学前端这么久最怕什么,那我的回答一定是写css。好在接触了elementui等工具之后,css写的少了,但是这仍是绕不开的东西。css最令人讨厌的莫过于其牵一发而动全身的性质,如果没有一个很清晰的结构,写css就是折磨自己。

所以,当我发现折叠出现问题的时候,我内心是崩溃的,不过好在是解决了。

bug原因

产生bug的原因很简单,el-menu希望它下面包裹的组件是el-menu-item或者el-sub-menu。但是我们的递归组件里包裹了一层div,所以bug就出现了。

解决

解决方法也不算困难,我们自己弄一个折叠功能不就好了吗。根据源码可以知道,element是采用修改sidebar-item的宽度来实现折叠的,这里我们采用修改sidebar-container来实现折叠。

在解决这个问题的过程中,我深刻体会到清晰的html结构是多么的重要。html结构如下

<div>
    <sidebar-container>
        <el-menu>
            <submenu-title-noDropdown>
                <item/>
            </submenu-title-noDropdown>
            <el-sub-menu>
                <item/>
            </el-sub-menu>
        </el-menu>
    </sidebar-container>
    <main-container>

    </main-container>
</div>
复制代码

我们想要实现折叠效果需要修改sidebar-containermain-container的宽度。实现方式就是,当我们点击折叠按钮时,给外层div附上新的class,进而修改两者的宽度。

//css
  //折叠前
  .main-container {
    transition: margin-left .28s;
    margin-left: 210px;
    position: relative;
  }
  .sidebar-container {
    transition: width 0.28s;
    width: 210px !important;
  }
  //折叠后
  .hideSidebar {
    .sidebar-container {
      width: 54px !important;
    }
    .main-container {
      margin-left: 54px;
    }
  }
//html
  <div :class="classObj">
    <sidebar class="sidebar-container" />
    <div class="main-container">
      <navbar />
      <app-main />
    </div>
 </div>
//js
let classObj = computed(() => {
      return {
        hideSidebar: store.getters.isCollapse,
        openSidebar: !store.getters.isCollapse,
      }
    })
复制代码

之后我们需要把标题部分隐藏,只留下图标部分,同时统一一下两种状态下图标的位置即可

  //折叠前的样式
  .sidebar-container {
    .el-menu {
      border: none;
      height: 100%;
      width: 100%;
      span {
        position: absolute;
        left: 54px;
      }
    }
  }
  //折叠后的样式
  .hideSidebar {
    .el-sub-menu {
      overflow: hidden;
      
      &>.el-sub-menu__title {
        padding: 0 !important;

        .svg-icon {
          margin-left: 20px;
        }

        .sub-el-icon {
          margin-left: 19px;
        }

        .el-sub-menu__icon-arrow {
          display: none;
        }
      }
    }

    .el-menu--collapse {
      .el-sub-menu {
        &>.el-sub-menu__title {
          &>span {
            height: 0;
            width: 0;
            overflow: hidden;
            visibility: hidden;
            display: inline-block;
          }
        }
      }
    }

    .submenu-title-noDropdown {
      padding: 0 !important;
      position: relative;

      .svg-icon {
        margin-left: 20px;
      }

      .sub-el-icon {
        margin-left: 19px;
      }

      span {
        height: 0;
        width: 0;
        overflow: hidden;
        visibility: hidden;
        display: inline-block;
      }

    }
复制代码

至此,sidebar功能完成

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享