递归函数 Vue ElementUI
对树形菜单的递归操作,首先应该对树形菜单数据进行整理,优化成自己需要的类型
比如Vue + ElementUI的动态侧边栏数据
1 export function routerRoleToPretty (routing = [], deepPath = '/main/') { 2 return routing.map(item => { 3 if (item instanceof Array) { // 由于后台返回数据问题 所以这里给了一个兼容判断 4 return item[0] 5 } else { 6 return item 7 } 8 }).map(item => { 9 return { 10 id: item.id, 11 path: item.path, 12 name: item.name, // 也可通过name方式跳转 13 fullPath: `${deepPath + item.path}`, // 这里我们获取到VueRouter的绝对路由 通过path的方式去进行跳转页面 14 meta: { // meta 中参数用来确定显示问题 15 icon: item.icon, 16 childrenLength: item.ziJi_1 ? item.ziJi_1.length : 0, 17 enTitle: item.enTitle, 18 zhTitle: item.zhTitle, 19 desc: item.description, 20 type: item.type, 21 parentId: item.parentId 22 }, 23 children: routerRoleToPretty(item.ziJi_1 ? item.ziJi_1 : [], deepPath + item.path + '/') 24 } 25 }) 26 }
由于后台返回的数据格式是 [[{}], [{}]]格式所以第一次需要将数据暴露出
这样一个递归就完成了数据处理
当然如果你想将递归数据全部取出来EcmaScript提供了一个方法 Array.prototype.flat()
var arr1 = [1, 2, [3, 4]]; arr1.flat(); // [1, 2, 3, 4]当参数为 Infinity 时不限制递归数据深度 这样就可以获取到所有队规的对象 然后再去 map() 操作就很简单啦
var arr3 = [1, 2, [3, 4, [5, 6]]]; // 使用 Infinity 作为深度,展开任意深度的嵌套数组 arr3.flat(Infinity); // [1, 2, 3, 4, 5, 6]
最后贴上ElementUI如何使用递归数据
父级组件
1 <!-- 左侧菜单导航栏组件 --> 2 <template> 3 <scroll-bar> 4 <slot></slot> 5 <div class="app-nav-wrap"> 6 <el-menu mode="vertical" 7 popper-class="roleMenuClass" 8 :default-active="routerAction" 9 :class="{'menu-nav': true, 'isCollapse': isCollapse}" 10 :unique-opened="true" 11 @open="handleOpen" 12 @close="handleClose" 13 :collapse="isCollapse" 14 background-color="#0A70F8" 15 text-color="#fff" 16 router> 17 <rm-menu :childrenData="routerMenu"></rm-menu> 18 </el-menu> 19 </div> 20 </scroll-bar> 21 </template> 22 23 <script> 24 import { mapGetters, mapActions } from 'vuex' 25 import SystemConfigModule from '@/utils/api/System' 26 import RmMenu from './RecursiveMenu' 27 import ScrollBar from '@/components/common/ScrollBar' 28 // import { getHistoryRouter } from '@/utils/cookie' 29 export default { 30 components: { RmMenu, ScrollBar }, 31 data () { 32 return { 33 routerMenu: [], 34 routerAction: this.$route.path 35 } 36 }, 37 watch: { 38 '$route' (to) { 39 this.routerAction = to.path 40 } 41 }, 42 created () { 43 this.rulesChange() 44 }, 45 computed: { 46 ...mapGetters([ 47 'sliderbar' 48 ]), 49 options () { 50 return this.$store.state.options 51 }, 52 isCollapse () { 53 return this.sliderbar 54 } 55 }, 56 methods: { 57 ...mapActions({ 58 UpdateRouterRole: 'UpdateRouterRole' 59 }), 60 handleOpen (key, keyPath) { 61 // console.log(key, keyPath) 62 }, 63 handleClose (key, keyPath) { 64 // console.log(key, keyPath) 65 }, 66 async rulesChange () { 67 this.routerMenu = await this.UpdateRouterRole(SystemConfigModule.SystemModule.MenuRole) 68 // console.log(this.routerMenu) 69 } 70 } 71 } 72 </script> 73 <style lang="scss" scoped> 74 @import '@/assets/sass/theme.sass'; 75 /deep/ .app-nav-wrap { 76 .menu-nav:not(.el-menu--collapse) { 77 width: 200px; 78 // min-height: 400px; 79 min-width: 36px; 80 .menulist { 81 background-color: $menuBg !important; 82 transition: all .5s linear; 83 // 展开样式 84 .el-submenu.is-opened { 85 .el-menu.el-menu--inline { 86 .el-menu-item { 87 background-color: $subMenuBg !important; 88 transition: all .5s linear; 89 &.is-active { 90 background-color: $menuHover !important; 91 transition: all .5s linear; 92 } 93 } 94 } 95 } 96 // 样式 97 li.el-menu-item,.el-submenu__title { 98 &:hover { 99 background-color: $menuHover; 100 transition: all .5s linear; 101 } 102 } 103 // 高亮 104 a.router-link-active li.el-menu-item.is-active, 105 .el-menu-item.is-active{ 106 background-color: $menuHover !important; 107 transition: all .5s linear; 108 } 109 .el-submenu__title, 110 .el-menu-item { 111 color: $fontColor; 112 transition: all .5s linear; 113 } 114 .el-submenu__icon-arrow.el-icon-arrow-down { 115 color: $fontColor; 116 } 117 } 118 } 119 // 小的菜单栏数据 120 .isCollapse{ 121 width: 36px; 122 .menulist{ 123 background-color: $menuBg !important; 124 transition: all .5s linear; 125 .el-submenu .el-submenu__title{ 126 padding: 0 !important; 127 span{ 128 display: none; 129 } 130 .icon-menu{ 131 margin: 0; 132 font-size: 16px; 133 padding: 15px 8px; 134 } 135 i.el-submenu__icon-arrow{ 136 display: none; 137 color: $fontColor; 138 } 139 } 140 // 样式 141 li.el-menu-item{ 142 padding: 0 !important; 143 span{ 144 display: none; 145 } 146 .icon-menu{ 147 margin: 0; 148 font-size: 16px; 149 padding: 15px 8px; 150 } 151 } 152 // hover样式 153 li.el-menu-item,.el-submenu__title { 154 &:hover { 155 background-color: $menuHover; 156 transition: all .5s linear; 157 } 158 } 159 // 高亮 160 li.el-menu-item.is-active, 161 li.el-submenu.is-active { 162 background-color: $menuHover !important; 163 transition: all .5s linear; 164 // 更改默认继承 165 .el-submenu__title { 166 background-color: inherit !important; 167 } 168 } 169 } 170 } 171 .menulist a.router-link-exact-active.router-link-active li.el-menu-item.is-active{ 172 background-color: $menuHover !important; 173 transition: all .5s linear; 174 } 175 i.icon-menu { 176 color: #fff; 177 } 178 } 179 </style> 180 <style lang="scss"> 181 @import '@/assets/sass/theme.sass'; 182 .roleMenuClass { 183 .menulist { 184 background-color: $menuBg !important; 185 transition: all .5s linear; 186 // 展开样式 187 .el-submenu.is-opened { 188 .el-menu.el-menu--inline { 189 .el-menu-item { 190 background-color: $subMenuBg !important; 191 transition: all .5s linear; 192 &.is-active { 193 background-color: $menuHover !important; 194 transition: all .5s linear; 195 } 196 } 197 } 198 } 199 li.el-menu-item,.el-submenu__title { 200 &:hover { 201 background-color: $menuHover; 202 transition: all .5s linear; 203 } 204 } 205 a.router-link-active li.el-menu-item.is-active, 206 .el-menu-item.is-active{ 207 background-color: $menuHover !important; 208 transition: all .5s linear; 209 } 210 .el-submenu__title, 211 .el-menu-item { 212 color: $fontColor; 213 transition: all .5s linear; 214 } 215 .el-submenu__icon-arrow.el-icon-arrow-down { 216 color: $fontColor; 217 } 218 } 219 /deep/ .menulist a.router-link-exact-active.router-link-active li.el-menu-item.is-active{ 220 background-color: $menuHover !important; 221 transition: all .5s linear; 222 } 223 i.icon-menu { 224 color: #fff; 225 } 226 } 227 </style>
子组件 RecursiveMenu.vue
1 <template> 2 <section class="menulist"> 3 <section v-for="item in childrenData" :key="item.id"> 4 <!-- 没有子集的 --> 5 <el-menu-item :index="item.fullPath" v-if="item.meta.childrenLength === 0"> 6 <i :class="['icon-menu', 'iconfont', item.meta.icon]"></i> 7 <span>{{langChange() ? item.meta.zhTitle : item.meta.enTitle}}</span> 8 </el-menu-item> 9 <!-- 子集只有一个的 只展示子集 --> 10 <el-menu-item :index="item.children[0].fullPath" v-if="item.meta.childrenLength === 1"> 11 <i :class="['icon-menu', 'iconfont', item.meta.icon]"></i> 12 <span>{{langChange() ? item.children[0].meta.zhTitle : item.children[0].meta.enTitle}}</span> 13 </el-menu-item> 14 <!-- 子集大于一个的 --> 15 <el-submenu :popper-append-to-body="true" popper-class="roleMenuClass" v-if="item.meta.childrenLength > 1" :index="item.fullPath"> 16 <template slot="title"> 17 <i :class="['icon-menu', 'iconfont', item.meta.icon]"></i> 18 <span v-if="item.meta && item.meta.zhTitle && item.meta.enTitle">{{langChange() ? item.meta.zhTitle : item.meta.enTitle}}</span> 19 </template> 20 <rm-menu :childrenData="item.children"></rm-menu> 21 </el-submenu> 22 </section> 23 </section> 24 </template> 25 <script> 26 import { mapGetters } from 'vuex' 27 export default { 28 name: 'RmMenu', 29 data () { 30 return {} 31 }, 32 computed: { 33 ...mapGetters([ 34 'lang' 35 ]) 36 }, 37 props: { 38 childrenData: { 39 default: () => [], 40 type: Array 41 } 42 }, 43 methods: { 44 langChange () { 45 if (this.lang === 'zh') { 46 return true 47 } else { 48 return false 49 } 50 } 51 } 52 } 53 </script>
至此结束