Рекурсивное меню на vue 3 в виде "дерева"

Рейтинг: -2Ответов: 2Опубликовано: 22.07.2023

Построение меню по v-for для случая много-уровневых данных

Ответы

▲ 0
Tree Component

<template>
<div class="flexCol">
<template v-for="item in listOfTrees">
 <template v-for="(value, key) in item">
    <div v-if="key === 'name'" class="group">Name: {{value}}</div>
    <template v-else-if="key === 'children'">
       <Menutree :menuPart="value"></Menutree>
    </template>
 </template>
 </template>
</div>
</template>

<script setup>
import {ref} from 'vue'
import Menutree from './Menutree'

const listOfTrees = ref( [{
  name: 'My Tree 2',
 children: [
 {name: 'hello1'},
 {name: 'world1'},
 {
    name: 'child of My Tree 2',
    children: [
       {
          name: 'child 1 of child of My Tree 2',
          children: [{name: 'hello'}, {name: 'world'}]
       },
    ]
 }
]
}, {
name: 'My Tree',
children: [
 {name: 'hello'},
 {name: 'world'},
 {
    name: 'child of My Tree ',
    children: [
       {
          name: 'child 1  of child of My Tree',
          children: [{name: 'hello'}, {name: 'world'}]
       },
       {name: 'hello'},
       {name: 'world'},
       {
          name: 'child 2  of child of My Tree',
          children: [{name: 'hello'}, {name: 'world'}]
       }
    ]
 }
]
}
])
</script>

<style scoped>
.flexCol {
  display: flex;
  flex-direction: column;
  justify-content: flex-start;
  align-items: flex-start;
 }
.group {
   width: 10rem;
   text-align: center;
   background-color: #97e6f3;
   padding: 0.25rem 0;
   margin: 0.25rem;
}

</style>

Module - Menutree 
<template>
<div class="flexCol">
<template v-for="item in menuPart">
 <template v-for="(valueBase, keyBase) in item">
    <div v-if="keyBase === 'name'" style="margin-left: 3rem" 
    class="subGroup">Name: {{valueBase}}</div>
    <template v-else-if="keyBase === 'children'">
       <template v-for="subitem in valueBase">
          <div v-if="subitem['name']" style="margin-left: 6rem" 
          class="subSubGroup">SubName: {{subitem['name']}}</div>
          <Menutree :menuPart="subitem['children']" style="margin- 
           left:6rem; background-color: lightyellow"></Menutree>
       </template>
    </template>
 </template>
</template>
</div>
</template>

<script setup>
import {ref} from 'vue'

defineProps(['menuPart'])

</script>

<style scoped>
.flexCol {
  display: flex;
  flex-direction: column;
  justify-content: flex-start;
  align-items: flex-start;
}
.subGroup {
  width: auto;
  text-align: left;
  background-color: #f4e1cc;
  padding: 0.25rem;
  margin: 0.25rem 3rem;
}
.subSubGroup {
  width: auto;
  text-align: left;
  background-color: #d6f4cc;
  padding: 0.25rem;
  margin: 0.25rem 6rem;
}
</style>
▲ 0

Ранее я привел пример для случая неизвестной вложенности данных. Однако, если Вы точно знаете что максимальный уровень вложенности - 3 (это достаточно для меню, например), то тогда вообще все проще и удобнее для стилизации и обработки событий.

<template>
 <div class="flexCol">
  <template v-for="item in listOfTrees">
     <template v-for="(value, key) in item">
        <div v-if="key === 'name'" class="group">Name: {{value}}</div>
        <template v-if="key === 'children' && value.length > 0">
           <template v-for="sub1 in value">
              <div v-if="sub1['name']" style="margin-left: 3rem">Sub1: {{sub1['name']}}</div>
              <template v-if="sub1['children']?.length > 0">
                 <template v-for="sub2 in sub1['children']">
                    <div v-if="sub2['name']" style="margin-left: 6rem">Sub2: {{sub2['name']}}</div>
                    <template v-if="sub2['children']?.length > 0">
                       <div v-for="sub3 in sub2['children']">
                          <div v-if="sub3['name']" style="margin-left: 9rem">Sub3: {{sub3['name']}}</div>
                       </div>
                    </template>
                 </template>
              </template>
           </template>
        </template>
     </template>
  </template>
 </div>
</template>