递归函数 Vue ElementUI

时间:2023-03-09 00:26:52
递归函数  Vue ElementUI

对树形菜单的递归操作,首先应该对树形菜单数据进行整理,优化成自己需要的类型

比如Vue + ElementUI的动态侧边栏数据

 export function routerRoleToPretty (routing = [], deepPath = '/main/') {
return routing.map(item => {
if (item instanceof Array) { // 由于后台返回数据问题 所以这里给了一个兼容判断
return item[0]
} else {
return item
}
}).map(item => {
return {
id: item.id,
path: item.path,
name: item.name, // 也可通过name方式跳转
fullPath: `${deepPath + item.path}`, // 这里我们获取到VueRouter的绝对路由 通过path的方式去进行跳转页面
meta: { // meta 中参数用来确定显示问题
icon: item.icon,
childrenLength: item.ziJi_1 ? item.ziJi_1.length : 0,
enTitle: item.enTitle,
zhTitle: item.zhTitle,
desc: item.description,
type: item.type,
parentId: item.parentId
},
children: routerRoleToPretty(item.ziJi_1 ? item.ziJi_1 : [], deepPath + item.path + '/')
}
})
}

由于后台返回的数据格式是 [[{}], [{}]]格式所以第一次需要将数据暴露出

这样一个递归就完成了数据处理

当然如果你想将递归数据全部取出来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如何使用递归数据

父级组件

 <!-- 左侧菜单导航栏组件 -->
<template>
<scroll-bar>
<slot></slot>
<div class="app-nav-wrap">
<el-menu mode="vertical"
popper-class="roleMenuClass"
:default-active="routerAction"
:class="{'menu-nav': true, 'isCollapse': isCollapse}"
:unique-opened="true"
@open="handleOpen"
@close="handleClose"
:collapse="isCollapse"
background-color="#0A70F8"
text-color="#fff"
router>
<rm-menu :childrenData="routerMenu"></rm-menu>
</el-menu>
</div>
</scroll-bar>
</template> <script>
import { mapGetters, mapActions } from 'vuex'
import SystemConfigModule from '@/utils/api/System'
import RmMenu from './RecursiveMenu'
import ScrollBar from '@/components/common/ScrollBar'
// import { getHistoryRouter } from '@/utils/cookie'
export default {
components: { RmMenu, ScrollBar },
data () {
return {
routerMenu: [],
routerAction: this.$route.path
}
},
watch: {
'$route' (to) {
this.routerAction = to.path
}
},
created () {
this.rulesChange()
},
computed: {
...mapGetters([
'sliderbar'
]),
options () {
return this.$store.state.options
},
isCollapse () {
return this.sliderbar
}
},
methods: {
...mapActions({
UpdateRouterRole: 'UpdateRouterRole'
}),
handleOpen (key, keyPath) {
// console.log(key, keyPath)
},
handleClose (key, keyPath) {
// console.log(key, keyPath)
},
async rulesChange () {
this.routerMenu = await this.UpdateRouterRole(SystemConfigModule.SystemModule.MenuRole)
// console.log(this.routerMenu)
}
}
}
</script>
<style lang="scss" scoped>
@import '@/assets/sass/theme.sass';
/deep/ .app-nav-wrap {
.menu-nav:not(.el-menu--collapse) {
width: 200px;
// min-height: 400px;
min-width: 36px;
.menulist {
background-color: $menuBg !important;
transition: all .5s linear;
// 展开样式
.el-submenu.is-opened {
.el-menu.el-menu--inline {
.el-menu-item {
background-color: $subMenuBg !important;
transition: all .5s linear;
&.is-active {
background-color: $menuHover !important;
transition: all .5s linear;
}
}
}
}
// 样式
li.el-menu-item,.el-submenu__title {
&:hover {
background-color: $menuHover;
transition: all .5s linear;
}
}
// 高亮
a.router-link-active li.el-menu-item.is-active,
.el-menu-item.is-active{
background-color: $menuHover !important;
transition: all .5s linear;
}
.el-submenu__title,
.el-menu-item {
color: $fontColor;
transition: all .5s linear;
}
.el-submenu__icon-arrow.el-icon-arrow-down {
color: $fontColor;
}
}
}
// 小的菜单栏数据
.isCollapse{
width: 36px;
.menulist{
background-color: $menuBg !important;
transition: all .5s linear;
.el-submenu .el-submenu__title{
padding: 0 !important;
span{
display: none;
}
.icon-menu{
margin: 0;
font-size: 16px;
padding: 15px 8px;
}
i.el-submenu__icon-arrow{
display: none;
color: $fontColor;
}
}
// 样式
li.el-menu-item{
padding: 0 !important;
span{
display: none;
}
.icon-menu{
margin: 0;
font-size: 16px;
padding: 15px 8px;
}
}
// hover样式
li.el-menu-item,.el-submenu__title {
&:hover {
background-color: $menuHover;
transition: all .5s linear;
}
}
// 高亮
li.el-menu-item.is-active,
li.el-submenu.is-active {
background-color: $menuHover !important;
transition: all .5s linear;
// 更改默认继承
.el-submenu__title {
background-color: inherit !important;
}
}
}
}
.menulist a.router-link-exact-active.router-link-active li.el-menu-item.is-active{
background-color: $menuHover !important;
transition: all .5s linear;
}
i.icon-menu {
color: #fff;
}
}
</style>
<style lang="scss">
@import '@/assets/sass/theme.sass';
.roleMenuClass {
.menulist {
background-color: $menuBg !important;
transition: all .5s linear;
// 展开样式
.el-submenu.is-opened {
.el-menu.el-menu--inline {
.el-menu-item {
background-color: $subMenuBg !important;
transition: all .5s linear;
&.is-active {
background-color: $menuHover !important;
transition: all .5s linear;
}
}
}
}
li.el-menu-item,.el-submenu__title {
&:hover {
background-color: $menuHover;
transition: all .5s linear;
}
}
a.router-link-active li.el-menu-item.is-active,
.el-menu-item.is-active{
background-color: $menuHover !important;
transition: all .5s linear;
}
.el-submenu__title,
.el-menu-item {
color: $fontColor;
transition: all .5s linear;
}
.el-submenu__icon-arrow.el-icon-arrow-down {
color: $fontColor;
}
}
/deep/ .menulist a.router-link-exact-active.router-link-active li.el-menu-item.is-active{
background-color: $menuHover !important;
transition: all .5s linear;
}
i.icon-menu {
color: #fff;
}
}
</style>

子组件 RecursiveMenu.vue

 <template>
<section class="menulist">
<section v-for="item in childrenData" :key="item.id">
<!-- 没有子集的 -->
<el-menu-item :index="item.fullPath" v-if="item.meta.childrenLength === 0">
<i :class="['icon-menu', 'iconfont', item.meta.icon]"></i>
<span>{{langChange() ? item.meta.zhTitle : item.meta.enTitle}}</span>
</el-menu-item>
<!-- 子集只有一个的 只展示子集 -->
<el-menu-item :index="item.children[0].fullPath" v-if="item.meta.childrenLength === 1">
<i :class="['icon-menu', 'iconfont', item.meta.icon]"></i>
<span>{{langChange() ? item.children[0].meta.zhTitle : item.children[0].meta.enTitle}}</span>
</el-menu-item>
<!-- 子集大于一个的 -->
<el-submenu :popper-append-to-body="true" popper-class="roleMenuClass" v-if="item.meta.childrenLength > 1" :index="item.fullPath">
<template slot="title">
<i :class="['icon-menu', 'iconfont', item.meta.icon]"></i>
<span v-if="item.meta && item.meta.zhTitle && item.meta.enTitle">{{langChange() ? item.meta.zhTitle : item.meta.enTitle}}</span>
</template>
<rm-menu :childrenData="item.children"></rm-menu>
</el-submenu>
</section>
</section>
</template>
<script>
import { mapGetters } from 'vuex'
export default {
name: 'RmMenu',
data () {
return {}
},
computed: {
...mapGetters([
'lang'
])
},
props: {
childrenData: {
default: () => [],
type: Array
}
},
methods: {
langChange () {
if (this.lang === 'zh') {
return true
} else {
return false
}
}
}
}
</script>

至此结束