简体   繁体   中英

How can you generate a Vue component for each level of a nested JSON object when you don't know how many there will be?

I have some JSON data that contains a list of retailers and some of these retailers have subretailers that can go many levels deep.

I would like to use Vue to generate markup that will display the parent retailer and then the nested subretailers below it similar to this:

在此处输入图片说明

I would like to create a function that will accommodate for as many nested retailers as there are in the JSON. Here is what the JSON looks like:

    [{
      "RetailerChilderen":[

      ],
      "Id":83107,
      "Name":"10-11",
      "HasInsightsCenter":true,
      "ParentId":0,
      "UserSelected":true,
      "UserHasAccess":true,
      "Letter":"#",
      "IsVisible":true,
      "InDepthLevel":0
   },
   {
      "RetailerChilderen":[

      ],
      "Id":82800,
      "Name":"1-800-Flowers.com",
      "HasInsightsCenter":false,
      "ParentId":0,
      "UserSelected":true,
      "UserHasAccess":true,
      "Letter":"#",
      "IsVisible":true,
      "InDepthLevel":0
   },
   {
      "RetailerChilderen":[
         {
            "RetailerChilderen":[
               {
                  "RetailerChilderen":[

                  ],
                  "Id":82371,
                  "Name":"Hervis Sports",
                  "HasInsightsCenter":false,
                  "ParentId":82247,
                  "UserSelected":false,
                  "UserHasAccess":false,
                  "Letter":null,
                  "IsVisible":true,
                  "InDepthLevel":0
               }
            ],
            "Id":82247,
            "Name":"Spar Austria",
            "HasInsightsCenter":false,
            "ParentId":648,
            "UserSelected":false,
            "UserHasAccess":false,
            "Letter":null,
            "IsVisible":true,
            "InDepthLevel":0
         },
         {
            "RetailerChilderen":[
               {
                  "RetailerChilderen":[

                  ],
                  "Id":655,
                  "Name":"Despar Italy",
                  "HasInsightsCenter":false,
                  "ParentId":83095,
                  "UserSelected":false,
                  "UserHasAccess":false,
                  "Letter":null,
                  "IsVisible":true,
                  "InDepthLevel":0
               },
               {
                  "RetailerChilderen":[

                  ],
                  "Id":82250,
                  "Name":"Spar Slovenia",
                  "HasInsightsCenter":false,
                  "ParentId":83095,
                  "UserSelected":false,
                  "UserHasAccess":false,
                  "Letter":null,
                  "IsVisible":true,
                  "InDepthLevel":0
               },
               {
                  "RetailerChilderen":[

                  ],
                  "Id":82370,
                  "Name":"Spar Hungary",
                  "HasInsightsCenter":false,
                  "ParentId":83095,
                  "UserSelected":false,
                  "UserHasAccess":false,
                  "Letter":null,
                  "IsVisible":true,
                  "InDepthLevel":0
               },
               {
                  "RetailerChilderen":[

                  ],
                  "Id":82374,
                  "Name":"Spar Croatia",
                  "HasInsightsCenter":false,
                  "ParentId":83095,
                  "UserSelected":false,
                  "UserHasAccess":false,
                  "Letter":null,
                  "IsVisible":true,
                  "InDepthLevel":0
               }
            ],
            "Id":83095,
            "Name":"SPAR ASPIAG",
            "HasInsightsCenter":false,
            "ParentId":648,
            "UserSelected":false,
            "UserHasAccess":false,
            "Letter":null,
            "IsVisible":true,
            "InDepthLevel":0
         }
      ],
      "Id":648,
      "Name":"Spar International",
      "HasInsightsCenter":true,
      "ParentId":0,
      "UserSelected":false,
      "UserHasAccess":false,
      "Letter":"S",
      "IsVisible":true,
      "InDepthLevel":0
   },
   {
      "RetailerChilderen":[

      ],
      "Id":860,
      "Name":"36.6 (Pharmacy)",
      "HasInsightsCenter":false,
      "ParentId":0,
      "UserSelected":false,
      "UserHasAccess":false,
      "Letter":"#",
      "IsVisible":true,
      "InDepthLevel":0
   },
   {
      "RetailerChilderen":[

      ],
      "Id":82926,
      "Name":"Ace Hardware Indonesia",
      "HasInsightsCenter":false,
      "ParentId":0,
      "UserSelected":false,
      "UserHasAccess":false,
      "Letter":"A",
      "IsVisible":true,
      "InDepthLevel":0
   }]

Right now in the code, I only loop through two levels and that is through the markup in Vue:

<ul class="item-container">
    <li v-for="item in retailers">

        <div class="item-info">
            <span>{{ item.Name }}</span>
        </div>

        <ul v-if="item.RetailerChilderen.length">
            <li v-for="subItem in item.RetailerChilderen">
                <div class="item-info">
                    <span>{{ subItem.Name }}</span>
                </div>
            </li>
        </ul>

    </li>
</ul>

Wouuld using a Vue template that is generated by a method be the correct method to allow for multiple levels of nested JSON to be displayed in the DOM?

You can just use a recursive component as you would with manipulating a node and its children.

 const RetailerRec = Vue.component('RetailerRec', { props: ['retailer'], template: ` <ul> <li> <input type="checkbox"/> {{retailer.Name}} </li> <template v-for="retailer in retailer.RetailerChilderen"> <RetailerRec :retailer="retailer"/> </template> </ul> ` }) const tree = JSON.parse('[{"RetailerChilderen":[],"Id":83107,"Name":"10-11","HasInsightsCenter":true,"ParentId":0,"UserSelected":true,"UserHasAccess":true,"Letter":"#","IsVisible":true,"InDepthLevel":0},{"RetailerChilderen":[],"Id":82800,"Name":"1-800-Flowers.com","HasInsightsCenter":false,"ParentId":0,"UserSelected":true,"UserHasAccess":true,"Letter":"#","IsVisible":true,"InDepthLevel":0},{"RetailerChilderen":[{"RetailerChilderen":[{"RetailerChilderen":[],"Id":82371,"Name":"Hervis Sports","HasInsightsCenter":false,"ParentId":82247,"UserSelected":false,"UserHasAccess":false,"Letter":null,"IsVisible":true,"InDepthLevel":0}],"Id":82247,"Name":"Spar Austria","HasInsightsCenter":false,"ParentId":648,"UserSelected":false,"UserHasAccess":false,"Letter":null,"IsVisible":true,"InDepthLevel":0},{"RetailerChilderen":[{"RetailerChilderen":[],"Id":655,"Name":"Despar Italy","HasInsightsCenter":false,"ParentId":83095,"UserSelected":false,"UserHasAccess":false,"Letter":null,"IsVisible":true,"InDepthLevel":0},{"RetailerChilderen":[],"Id":82250,"Name":"Spar Slovenia","HasInsightsCenter":false,"ParentId":83095,"UserSelected":false,"UserHasAccess":false,"Letter":null,"IsVisible":true,"InDepthLevel":0},{"RetailerChilderen":[],"Id":82370,"Name":"Spar Hungary","HasInsightsCenter":false,"ParentId":83095,"UserSelected":false,"UserHasAccess":false,"Letter":null,"IsVisible":true,"InDepthLevel":0},{"RetailerChilderen":[],"Id":82374,"Name":"Spar Croatia","HasInsightsCenter":false,"ParentId":83095,"UserSelected":false,"UserHasAccess":false,"Letter":null,"IsVisible":true,"InDepthLevel":0}],"Id":83095,"Name":"SPAR ASPIAG","HasInsightsCenter":false,"ParentId":648,"UserSelected":false,"UserHasAccess":false,"Letter":null,"IsVisible":true,"InDepthLevel":0}],"Id":648,"Name":"Spar International","HasInsightsCenter":true,"ParentId":0,"UserSelected":false,"UserHasAccess":false,"Letter":"S","IsVisible":true,"InDepthLevel":0},{"RetailerChilderen":[],"Id":860,"Name":"36.6 (Pharmacy)","HasInsightsCenter":false,"ParentId":0,"UserSelected":false,"UserHasAccess":false,"Letter":"#","IsVisible":true,"InDepthLevel":0},{"RetailerChilderen":[],"Id":82926,"Name":"Ace Hardware Indonesia","HasInsightsCenter":false,"ParentId":0,"UserSelected":false,"UserHasAccess":false,"Letter":"A","IsVisible":true,"InDepthLevel":0}]') new Vue({ components: { RetailerRec }, data () { return { tree } }, template: `<div> <RetailerRec v-for="retailer in tree" :retailer="retailer" :key="retailer.Id"/> </div>`, el: '#app' })
 li{ list-style-type:none; }
 <script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script> <div id="app"></div>

Create a component for one item and use it itself to create subitems in v-for.

Something like this:

Item.vue

<template>
  <li>
  <div class="item-info">
    <span>{{ item.Name }}</span>
  </div>
  <ul v-if="item.RetailerChilderen.length">
   <item v-for="(subItem, index) in item.RetailerChilderen" :item="subItem" :key="index" />
  </ul>
  <li>
</template>

Root.vue

<ul class="item-container">
    <item v-for="(item, index) in retailers" :item="item">
</ul>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM