e框架中如何用递归方式做侧边栏导航?

Admin 2022-10-21 群英技术资讯 262 次浏览

在这篇文章中,我们来学习一下“e框架中如何用递归方式做侧边栏导航?”的相关知识,下文有详细的讲解,易于大家学习和理解,有需要的朋友可以借鉴参考,下面就请大家跟着小编的思路一起来学习一下吧。

早就实现了功能,但是发现点击的时候,选中的菜单项背景色会变白,周五时候仔细观察了一下,发现并不是调整样式的问题,而是选项没有被选中,于是好好研究了一下组件递归这块,总结记录一下心路历程

一、概念

递归:递归其实说白了,就是自己调用自己,样子就像是套娃一个套一个的,小时候玩过一个游戏汉诺塔就是利用的递归原理:

函数递归:函数利用函数名还调用自己
组件递归:所以组件递归利用的是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" >              <!--            <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 -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, path){        // alert(name)        this .$router.push(path)        this .$store.commit( 'common/updateMenuActiveName' , 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' ,    components: {      SideBarItem: () => import( '@/components/common/SideBarItem' )    },    data () {      return {      }    },    mounted () {    },    methods: {      foldSideBar(){        this .sidebarFold = ! this .sidebarFold        this .menuActiveName = 'NAV'      }    },    computed: {      menuList: {        get () {          return this .$store.state.common.menuList        },        set (val) {          this .$store.commit( 'common/updateMenuList' , val)        }      },      menuActiveName: {        get () {          console.log( this .$store.state.common.menuActiveName)          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 -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 || {}      }    },    data () {      return {        }    },    mounted () {    },    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" , "pid" : "0" , "code" : "WD" , "name" : "温度" , "path" : "/temperature" , "type" : null , "icon" : null , "sysId" : "2AB00274-73DF-459A-A02E-C79A4D8A8929" , "orderNo" :0, "isCheck" : null , "children" :[]},              { "id" : "73660AB4-48D3-4BDB-86FD-C8397D4D54EC" , "pid" : "0" , "code" : "BJ" , "name" : "报警" , "path" : "/alarm" , "type" : null , "icon" : null , "sysId" : "2AB00274-73DF-459A-A02E-C79A4D8A8929" , "orderNo" :0, "isCheck" : null ,                "children" :[                  { "id" : "1C99333D-886F-4AD6-93C4-7C5244E48247" , "pid" : "73660AB4-48D3-4BDB-86FD-C8397D4D54EC" , "code" : "FD" , "name" : "防盗" , "path" : "/burg" , "type" : null , "icon" : null , "sysId" : "3691C2E8-8848-4439-8899-9A8039AE6AB5" , "orderNo" :0, "isCheck" : null , "children" :[]},                  { "id" : "1DBDF678-F51F-444A-B995-61E5D9CCA5AF" , "pid" : "73660AB4-48D3-4BDB-86FD-C8397D4D54EC" , "code" : "JL" , "name" : "警铃" , "path" : "/bell" , "type" : null , "icon" : null , "sysId" : "3691C2E8-8848-4439-8899-9A8039AE6AB5" , "orderNo" :0, "isCheck" : null , "children" :[]},                  { "id" : "BFC8C2E1-0E5B-4EEE-B91D-3DABC63FF481" , "pid" : "73660AB4-48D3-4BDB-86FD-C8397D4D54EC" , "code" : "JS" , "name" : "浸水" , "path" : "/immersion" , "type" : null , "icon" : null , "sysId" : "3691C2E8-8848-4439-8899-9A8039AE6AB5" , "orderNo" :0, "isCheck" : null , "children" :[]},                  { "id" : "BFC8C2E1-0E5B-4EEE-B91D-3DABC63FF482" , "pid" : "73660AB4-48D3-4BDB-86FD-C8397D4D54EC" , "code" : "MJ" , "name" : "门禁" , "path" : "/punch" , "type" : null , "icon" : null , "sysId" : "3691C2E8-8848-4439-8899-9A8039AE6AB5" , "orderNo" :0, "isCheck" : null , "children" :[]},                  { "id" : "BFC8C2E1-0E5B-4EEE-B91D-3DABC63FF483" , "pid" : "73660AB4-48D3-4BDB-86FD-C8397D4D54EC" , "code" : "ZT" , "name" : "状态" , "path" : "/state" , "type" : null , "icon" : null , "sysId" : "3691C2E8-8848-4439-8899-9A8039AE6AB5" , "orderNo" :0, "isCheck" : null , "children" :[]}                ]              },              { "id" : "34161C2E8-7348-4439-8899-9A8039AE6AE5" , "pid" : "0" , "code" : "GZ" , "name" : "工作" , "path" : "/work" , "type" : null , "icon" : null , "sysId" : "3691C2E8-8848-4439-8899-9A8039AE6AB5" , "orderNo" :0, "isCheck" : null ,                "children" :[]              },              { "id" : "0CD6B09A-AA43-4AE9-9AC7-29BC5AC83495" , "pid" : "0" , "code" : "SJ" , "name" : "数据" , "path" : "/data" , "type" : null , "icon" : null , "sysId" : "2AB00274-73DF-459A-A02E-C79A4D8A8929" , "orderNo" :0, "isCheck" : null ,                "children" :[]              },              { "id" : "049C670D-A33E-4188-9206-B3F3B5DDE77B" , "pid" : "0" , "code" : "SP" , "name" : "视频" , "path" : "/video" , "type" : null , "icon" : null , "sysId" : "3691C2E8-8848-4439-8899-9A8039AE6AB5" , "orderNo" :0, "isCheck" : null , "children" :[]},              { "id" : "0A15DBB6-3241-4C7F-AAD4-5417E7BBECAA" , "pid" : "0" , "code" : "RZ" , "name" : "日志" , "path" : "/log" , "type" : null , "icon" : null , "sysId" : "2AB00274-73DF-459A-A02E-C79A4D8A8929" , "orderNo" :0, "isCheck" : null ,                "children" :[]              }            ]

效果如图:

折叠后如图:


上述内容具有一定的借鉴价值,感兴趣的朋友可以参考,希望能对大家有帮助,想要了解更多"e框架中如何用递归方式做侧边栏导航?"的内容,大家可以关注群英网络的其它相关文章。 群英智防CDN,智能加速解决方案
标签: vue侧边栏导航

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:mmqy2019@163.com进行举报,并提供相关证据,查实之后,将立刻删除涉嫌侵权内容。

猜你喜欢

成为群英会员,开启智能安全云计算之旅

立即注册
专业资深工程师驻守
7X24小时快速响应
一站式无忧技术支持
免费备案服务
免费拨打  400-678-4567
免费拨打  400-678-4567 免费拨打 400-678-4567 或 0668-2555555
在线客服
微信公众号
返回顶部
返回顶部 返回顶部
在线客服
在线客服