1. 程式人生 > 程式設計 >vue+elementUI元件遞迴實現可摺疊動態渲染多級側邊欄導航

vue+elementUI元件遞迴實現可摺疊動態渲染多級側邊欄導航

早就實現了功能,但是發現點選的時候,選中的選單項背景色會變白,週五時候仔細觀察了一下,發現並不是調整樣式的問題,而是選項沒有被選中,於是好好研究了一下元件遞迴這塊,總結記錄一下心路歷程

一、概念

遞迴:遞迴其實說白了,就是自己呼叫自己,樣子就像是套娃一個套一個的,小時候玩過一個遊戲漢諾塔就是利用的遞迴原理:

在這裡插入圖片描述

函式遞迴:函式利用函式名還呼叫自己
元件遞迴:所以元件遞迴利用的是vue元件中的name屬性來實現的

二、需求

實現可摺疊動態渲染多級側邊欄導航

三、分析

在這裡插入圖片描述

1、觀察到側邊欄導航是一級一級的,第二級就相當於再重複一遍第一級 2、有一個特點,有的選單有下級,有的沒有下一級 3、動態渲染,說明是從後臺介面獲取的樹型別資料,動態的渲染上去 四、程式碼實現 1、首先先執行一下文件裡的demo試一下:

文件:element文件

2、改成自己需要的樣式,第一次是這麼寫的

父元件SideBar

<template>
  <el-menu class="menu-wrap" :default-active="menuActiveName || 'home'" :active="menuActiveName || 'home'"
           :collapse="sidebarFold" :collapseTransition="false" :unique-opened="true" @select="selectItem">
    <template>
      <el-menu-item @click="sidebarFold = !sidebarFold">
        <i v-show="!sidebarFold" class="el-icon-s-fold"></i>
        <i v-show="sidebarFold" class="el-icon-s-unfold"></i>
        <span slot="title" class="sidebar-one">導航列表</span>
      </el-menu-item>
    </template>
<!--    <side-bar-item :list="menuList"></side-bar-item>-->
    <template v-for="(item,index) in menuList" class="menu">
      <!-- 標題 -->
      <template v-if="item.children.length" >
        <el-submenu :key="index" :index="item.id" class="sub-menu-item">
          <template :index="item.index" slot="title">
      http://www.cppcns.com
<!-- <i :class="item.icon"></i>--> <i class="iconfont icon-danganjianying"></i> <span>{{item.name}}</span> </template> <el-menu-item-group class="menu-item-group"> <side-bar-item :list="item.children"></side-bar-item> </el-menu-item-group> </el-submenu> </template> <!-- 選項 --> <template v-else> <el-menu-item :key="index" :index="item.id" class="menu-item"> <!-- <i :class="item.icon"></i>--> <i class="iconfont icon-danganjianying"></i> <span>{{item.name}}</span> </el-menu-item> </template> </template> </el-menu> </template> <script> export default { name: 'SideBar',components: { SideBarItem: () => import('@/components/common/SideBarItem') },data () { return { } },mounted () { },methods: { selectItem(name,path){ // alert(name) this.$router.push(path) this.$store.commit('common/updateMenuActiveName',name) } },computed: { menuList: { get () { return this.$store.state.common.menuList },set (val) { this.$store.commit('common/updateMenuList',val) } },menuActiveName: { get () { return this.$store.state.common.menuActiveName },set (val) { this.$store.commit('common/updateMenuActiveName',val) } },sidebarFold: { get() {return this.$store.state.common.sidebarFold;},set(val) {this.$store.commit("common/updateSidebarFold",val);} },},} </script> <style lang="less" scoped> .menu-wrap{ width: 200px; min-height: 1020px; background: url('../../assets/img/sidebar_bg.png') no-repeat; background-size: 100% 100%; } /deep/ .el-menu{ background-color: transparent !important; .iconfont { font-size: 18px; vertical-align: sub; margin-right: 5px; display: inline-block; width: 20px; text-align: center; } } /deep/ .el-menu-item,/deep/ .el-submenu__title{ color: #fff; .iconfont{ color: #fff; } } /deep/ .el-menu-item span,/deep/ .el-submenu__title span{ padding-left: 10px; } /deep/ .el-menu-item.is-active { -webkit-box-shadow: inset 5px 100px 0px -2px #0064B6; box-shadow: inset 5px 100px 0px http://www.cppcns.com
-2px #0064B6; } /deep/ .el-submenu__title:hover,/deep/ .el-menu-item:hover{ background: #0064B6; } /deep/ .el-menu-item-group__title{ padding: 0; } </style>

子元件SideBarItem

<template>
  <div class="menu">
    <template v-for="(item,index) in list">
      <!-- 標題 -->
      <template v-if="item.children.length" >
        <el-submenu :key="index" :index="item.id" class="sub-menu-item">
          <template :index="item.index" slot="title">
<!--            <i :class="item.icon"></i>-->
            <i class="iconfont icon-danganjianying"></i>
            <span>{{item.name}}</span>
          </template>
          <el-menu-item-group class="menu-item-group">
            <side-bar-item :list="item.children"></side-bar-item>
          </el-menu-item-group>
        </el-submenu>
      </template>
      <!-- 選項 -->
      <template v-else>
        <el-menu-item :key="index" :index="item.id" class="menu-item" @click="selectItem(item.name,item.path)">
<!--          <i :class="item.icon"></i>-->
          <i class="iconfont icon-danganjianying"></i>
          <span>{{item.name}}</span>
        </el-menu-item>
      </template>
    </template>
  </div>
</template>
<script>

export default {
  name: 'SideBarItem',// props: ['list'],props: {
    list: {
      type: Array || ''
    }
  },data () {
    return {
      treeData: [{
        label: '某某省程式設計客棧',children: [{
          label: '中共某某省委員會'
          // children: [{
          // label: '三級 1-1-1'
          // }]
        },{
          label: '中共某某省辦公室'
        },{
          label: '中共某某省組織部'
        }
        ]
      }
      ],isShow: false
      // menuList: []
    }
  },mounted () {
    this.loadSysMenu()
  },methods: {
    loadSysMenu () {
      // console.log('menu',this.menuList)
    },// personManage (name) {
    //   if (name === '人員管理') {
    //     this.isShow = !this.$store.state.common.rbflag
    //     // alert('111' + this.isShow)
    //     this.$store.commit('common/updateShowRbox',this.isShow)
    //   }
    // },selectItem(name,}
</script>
<style lang="less" scoped>
.menu{
  width: 100%;

  .sub-menu-item /deep/ .el-submenu__title,.menu-item{
    height: 60px;
    line-height: 60px;
    text-align: left;
    //padding-left: 30px !important;
    //border-bottom: 1px solid #000;
    //border-right: 1px solid #000;
    color: #fff;
  }

  .sub-menu-item .el-menu-item{
    padding-right: 0;
  }

 /deep/ .el-menu-item .is-active{
    background-color: #0087df;
  }

  .menu-item:hover,/deep/ .el-submenu__title:hover{
    background-color: #0087df;
  }

  .menu-item span,.sub-menu-item /deep/ .el-submenu__title>span{
    font-weight: 700;
  }

  .menu-item-group /deep/ .el-menu-item-group__title{
    padding: 0 !important;
  }

  .menu-item-group .menu-item{
    background: url('../../assets/img/sidebar_bg.png') no-repeat;
  }

  .el-menu-item-group span{
    font-weight: normal;
  }

}

</style>

後來發現摺疊不成功,而且選中之後選中項樣式沒變,後來發現是沒選中,研究發現是因為多嵌套了一層div,而且用了el-menu-item-group專案中並不需要這個,於是改進如下:

父元件SideBar

<template>
  <el-menu class="menu-wrap" :default-active="menuActiveName" :collapse="sidebarFold" :collapseTransition="false" :unique-opened="true">
    <template>
      <el-menu-item @click="foldSideBar">
        <i v-show="!sidebarFold" class="el-icon-s-fold"></i>
        <i v-show="sidebarFold" class="el-icon-s-unfold"></i>
        <span slot="title" class="sidebar-one">導航列表</span>
      </el-menu-item>
    </template>
    <side-bar-item v-for="menu in menuList" :key="menu.id" :menu="menu"></side-bar-item>
  </el-menu>
</template>

<script>

export default {
  name: 'SideBar',data () {
    return {
    }
  },methods: {
    foldSideBar(){
      this.sidebarFold = !this.sidebarFold
      this.menuActiveName = 'NAV'
    }
  },menuActiveName: {
      get () {
        console.log(this.$store.state.common.menuActiveName)
        return this.$store.state.common.menuActiveName
      },set (val) {
        this.$store.commit('common/updateMenuActiveName',}
</script>
<style lang="less" scoped>
.menu-wrap{
  width: 200px;
  min-height: 1020px;
  background: url('../../assets/img/sidebar_bg.png') no-repeat;
  background-size: 100% 100%;
}

/deep/ .el-menu{
  backgrxMokpQKJAound-color: transparent !important;
  .iconfont {
    font-size: 18px;
    vertical-align: sub;
    margin-right: 5px;
    display: inline-block;
    width: 20px;
    text-align: center;
  }
}

/deep/ .el-menu-item,/deep/ .el-submenu__title span{
  padding-left: 10px;
}

/deep/ .el-menu-item.is-active {
  -webkit-box-shadow: inset 5px 100px 0px -2px #0064B6;
  box-shadow: inset 5px 100px 0px -2px #0064B6;
}

/deep/ .el-submenu__title:hover,/deep/ .el-menu-item:hover{
  background: #0064B6;
}

</style>

子元件SideBarItem

<template>
    <!--    該選單下還有子選單-->
    <el-submenu v-if="menu.children.length" :index="menu.code" :popper-append-to-body=false>
        <template slot="title">
            <i class="iconfont icon-danganjianying"></i>
            <span>{{ menu.name }}</span>
        </template>
        <side-bar-item v-for="item in menu.children" :key="item.id" :menu="item"></side-bar-item>
    </el-submenu>
    <!--    該選單下無子選單-->
    <el-menu-item v-else :index="menu.code" @click="selectItem(menu.code,menu.path)">
        <i class="iconfont icon-danganjianying"></i>
        <span>{{ menu.name }}</span>
    </el-menu-item>
</template>
<script>

export default {
  name: 'SideBarItem',// props: ['menu'],props: {
      menu: {
      type: Object || {}
    }
  },methods: {
    selectItem(code,path){
      // alert(name)
      console.log(code,path)
      this.$router.push(path)
      this.$store.commit('common/updateMenuActiveName',code)
    }
  },}
</script>
<style lang="less" scoped>
.menu{
  width: 100%;

  .menu-item{
    height: 60px;
    line-height: 60px;
    text-align: left;
    color: #fff;
  }

  .sub-menu-item .el-menu-item{
    padding-right: 0;
  }

 /deep/ .el-menu-item .is-active{
    background-color: #0087df;
  }

  .menu-item:hover{
    background-color: #0087df;
  }

  .menu-item span{
    font-weight: 700;
  }

}

</style>

功能基本實現,但是出現一個bug,當滑鼠點摺疊時,會出現迴圈呼叫某個事件,導致棧溢位報錯,檢視文章只需對子選單設定屬性 :popper-append-to-body=“false” 即可
參考文章:Element-ui NavMenu子選單使用遞迴生成時使用報錯

最後附上簡單的測試資料:

testData: [
            {"id":"34161C2E8-7348-4439-8899-9A8039AE6AE4","pid":"0","code":"HOME","name":"首頁","path":"/home","type":null,"icon":null,"sysId":"2761C2E8-7348-4439-8899-9A8039AE6AE3","orderNo":0,"isCheck":null,"children":[]},{"id":"703DBEBD-F92C-4347-9203-F60A73153C3F","code":"WD","name":"溫度","path":"/temperature","sysId":"2AB00274-73DF-459A-A02E-C79A4D8A8929",{"id":"73660AB4-48D3-4BDB-86FD-C8397D4D54EC","code":"BJ","name":"報警","path":"/alarm","children":[
                {"id":"1C99333D-886F-4AD6-93C4-7C5244E48247","pid":"73660AB4-48D3-4BDB-86FD-C8397D4D54EC","code":"FD","name":"防盜","path":"/burg","sysId":"3691C2E8-8848-4439-889www.cppcns.com9-9A8039AE6AB5",{"id":"1DBDF678-F51F-444A-B995-61E5D9CCA5AF","code":"JL","name":"警鈴","path":"/bell","sysId":"3691C2E8-8848-4439-8899-9A8039AE6AB5",{"id":"BFC8C2E1-0E5B-4EEE-B91D-3DABC63FF481","code":"js","name":"浸水","path":"/immersion",{"id":"BFC8C2E1-0E5B-4EEE-B91D-3DABC63FF482","code":"MJ","name":"門禁","path":"/punch",{"id":"BFC8C2E1-0E5B-4EEE-B91D-3DABC63FF483","code":"ZT","name":"狀態","path":"/state","children":[]}
              ]
            },{"id":"34161C2E8-7348-4439-8899-9A8039AE6AE5","code":"GZ","name":"工作","path":"/work","children":[]
            },{"id":"0CD6B09A-AA43-4AE9-9AC7-29BC5AC83495","code":"SJ","name":"資料","path":"/data",{"id":"049C670D-A33E-4188-9206-B3F3B5DDE77B","code":"SP","name":"視訊","path":"/video",{"id":"0A15DBB6-3241-4C7F-AAD4-5417E7BBECAA","code":"RZ","name":"日誌","path":"/log","children":[]
            }
          ]

效果如圖:

在這裡插入圖片描述

摺疊後如圖:

在這裡插入圖片描述

到此這篇關於vue+elementUI元件遞迴實現可摺疊動態渲染多級側邊欄導航的文章就介紹到這了,更多相關elementUI可摺疊動態側邊欄導航內容請搜尋我們以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援我們!