Skip to content

Nesting

We can use recursive components to achieve nested effects

When using this feature, please note: When using nested components, the recursive component name should be consistent with the component name. It is recommended to use defineOptions({name:'ComponentName'}).

TIP

This chapter uses the custom two-way binding method. If you don’t know much about it, please refer to the information on custom two-way binding first. vue2 and vue3 are different.

Component Usage

  • item 1

    • item 2

    • item 3

      • item 4

      • item 5

        [
          {
            "name": "item 1",
            "children": [
              {
                "name": "item 2",
                "children": []
              }
            ]
          },
          {
            "name": "item 3",
            "children": [
              {
                "name": "item 4",
                "children": []
              }
            ]
          },
          {
            "name": "item 5",
            "children": []
          }
        ]
        Use Components

        NestedComponent.vue

        vue
        <template>
          <VueDraggable class="drag-area" tag="ul" v-model="list" group="g1">
            <li v-for="el in modelValue" :key="el.name">
              <p>{{ el.name }}</p>
              <nested-component v-model="el.children" />
            </li>
          </VueDraggable>
        </template>
        <script setup lang="ts">
        import { VueDraggable } from 'vue-draggable-plus'
        import { computed } from 'vue'
        
        interface IList {
          name: string
          children: IList[]
        }
        
        interface Props {
          modelValue: IList[]
        }
        
        const props = defineProps<Props>()
        
        interface Emits {
          (e: 'update:modelValue', value: IList[]): void
        }
        
        const emits = defineEmits<Emits>()
        const list = computed({
          get: () => props.modelValue,
          set: value => emits('update:modelValue', value)
        })
        </script>
        <style scoped>
        .drag-area {
          min-height: 50px;
          outline: 1px dashed;
        }
        </style>

        Function Usage

        • item 1

          • item 2

          • item 3

            • item 4

            • item 5

              [
                {
                  "name": "item 1",
                  "children": [
                    {
                      "name": "item 2",
                      "children": []
                    }
                  ]
                },
                {
                  "name": "item 3",
                  "children": [
                    {
                      "name": "item 4",
                      "children": []
                    }
                  ]
                },
                {
                  "name": "item 5",
                  "children": []
                }
              ]
              Pass function option implementation

              NestedFunction.vue

              vue
              <template>
                <ul class="drag-area" ref="el">
                  <li v-for="el in modelValue" :key="el.name">
                    <p>{{ el.name }}</p>
                    <nested-function v-model="el.children" />
                  </li>
                </ul>
              </template>
              <script setup lang="ts">
              import { useDraggable } from 'vue-draggable-plus'
              import { computed, ref } from 'vue'
              
              interface IList {
                name: string
                children: IList[]
              }
              
              interface Props {
                modelValue: IList[]
              }
              
              const props = defineProps<Props>()
              interface Emits {
                (e: 'update:modelValue', value: IList[]): void
              }
              const emits = defineEmits<Emits>()
              const list = computed({
                get: () => props.modelValue,
                set: value => emits('update:modelValue', value)
              })
              
              const el = ref()
              useDraggable(el, list, {
                group: 'g1'
              })
              </script>
              <style scoped>
              .drag-area {
                min-height: 50px;
                outline: 1px dashed;
              }
              </style>

              Directive Usage

              • item 1

                • item 2

                • item 3

                  • item 4

                  • item 5

                    [
                      {
                        "name": "item 1",
                        "children": [
                          {
                            "name": "item 2",
                            "children": []
                          }
                        ]
                      },
                      {
                        "name": "item 3",
                        "children": [
                          {
                            "name": "item 4",
                            "children": []
                          }
                        ]
                      },
                      {
                        "name": "item 5",
                        "children": []
                      }
                    ]
                    Usage DirectivePass command parameter implementation

                    NestedDirective.vue

                    vue
                    <template>
                      <ul v-draggable="[list, { group: 'g1' }]" class="drag-area">
                        <li v-for="el in modelValue" :key="el.name">
                          <p>{{ el.name }}</p>
                          <nested-directive v-model="el.children" />
                        </li>
                      </ul>
                    </template>
                    <script setup lang="ts">
                    import { vDraggable } from 'vue-draggable-plus'
                    import { computed } from 'vue'
                    
                    interface IList {
                      name: string
                      children: IList[]
                    }
                    
                    interface Props {
                      modelValue: IList[]
                    }
                    
                    const props = defineProps<Props>()
                    interface Emits {
                      (e: 'update:modelValue', value: IList[]): void
                    }
                    const emits = defineEmits<Emits>()
                    const list = computed({
                      get: () => props.modelValue,
                      set: value => emits('update:modelValue', value)
                    })
                    </script>
                    <style scoped>
                    .drag-area {
                      min-height: 50px;
                      outline: 1px dashed;
                    }
                    </style>