渲染未知深度的嵌套数组对象 VUE

时间:2021-06-23 14:32:52

标签: javascript vue.js user-interface

如何在 UI 上呈现和显示嵌套元素(来自对象的嵌套 value[] 字段),这些元素是在父元素中选择选项(例如列表)时动态生成的? 例如,我在下面得到了这个代码。当您创建字段并选择 List 选项时,您应该会看到一个嵌套等,深度未知。我怎样才能呈现这个以显示给用户? v-for 里面的那种 v-for 似乎不起作用。可能这里需要递归,但是不知道怎么释放。

感谢您的帮助!

var app = new Vue({
    el: '.container',
    data: {
        modelname: '',
                fields: []
    },
    methods: {

        addNewField() {
            this.fields.push({
            left: 0,
            type:'',
            method:'',
            size:'',
            value:''}
            )
        },
        createChildElement(field) {
        if (field.type == "List") {
        Vue.set(field, "value", []);
        field.value.push({
                   type:'',
                   left: field.left+20,
                   method:'',
                   size:'',
                   value:''}
                   );
 }
        
        },
        showJson() {
        const data = this.fields
    alert(JSON.stringify(data, null, 2));
        }
    }
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div class="container">
            <h1 class="font-italic text-warning">TDGT Web Client</h1>
            <!--<button id="add-model" class="btn btn-warning" @click="addNewModel">Создать модель</button>-->
            <div>
                <button id="add-field" class="btn btn-sm btn-warning" @click="addNewField">Create field</button>
                <button id="show-json" class="btn btn-sm btn-warning" @click="showJson">Show JSON</button>
                <div v-for="(field, index) in fields" :style="{marginLeft: field.left+'px'}" :key="index">
                    <ul>
                        <li>
                    <select  v-model="field.type" v-on:change="createChildElement(field)"  aria-label="Выбрать тип поля">
                        <option selected>Тип поля</option>
                        <option value="List">List</option>
                        <option value="Map">Map</option>
                        <option value="Integer">Integer</option>
                    </select>
                    <select  v-model="field.method" v-if="field.type === 'Map' || field.type === 'List'"  aria-label="Метод генерации">
                        <option selected>Тип значения</option>
                        <option value="Static">Static</option>
                        <option value="Random">Random</option>
                        <option value="Range">Range</option>
                    </select>
                    <input type="text" v-if="field.type === 'Map' || field.type === 'List'"  v-model="field.size" placeholder="Размерность">
                    <input type="text" v-if="field.type === 'Integer'"  v-model="field.value" placeholder="Значение">
                        </li>
                        <ul></ul>
                    </ul>
                </div>

            </div>
    </div>

UPD。根据答案,我尝试为我的任务制定解决方案,但我仍然遇到一些问题。我将大部分代码移到了组件中,但是我收到了很多无法解决的错误。例如:

Invalid prop: type check failed for prop "item". Expected Object, got Array.


Property or method "fields" is not defined on the instance but referenced during render.

这是我的代码:

      Vue.component("el-inpt-group", {
        template: "#item-template",
        props: {
            item: Object,
          }
          });



var app = new Vue({
    el: '.container',
    data: {
        modelname: '',
        fields: [
        ]
    },
    methods: {

        addNewField() {
            this.fields.push({
            name: '',
            left: 0,
            type:'',
            method:'',
            size:'',
            value:''}
            )
        },
        createChildElement(field) {
        if (field.type == "List") {
        Vue.set(field, "value", []);
        field.value.push({
        name: '',
                   type:'',
                   left: field.left+20,
                   method:'',
                   size:'',
                   value:''}
                   )
        }
        },
        showJson() {
        const data = this.fields
    alert(JSON.stringify(data, null, 2));
        }
    }
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>


    <script type="text/x-template" id="item-template">
            <ul>
                <li v-for="field in fields">
                    <input type="text"  v-model="field.name" placeholder="Name">
                    <select  v-model="field.type" v-on:change="createChildElement(field)"  aria-label="Выбрать тип поля">
                        <option selected>Тип поля</option>
                        <option value="List">List</option>
                        <option value="Map">Map</option>
                        <option value="Integer">Integer</option>
                    </select>
                    <select  v-model="field.method" v-if="field.type === 'Map' || field.type === 'List'"  aria-label="Метод генерации">
                        <option selected>Тип значения</option>
                        <option value="Static">Static</option>
                        <option value="Random">Random</option>
                        <option value="Range">Range</option>
                    </select>
                    <input type="text" v-if="field.type === 'Map' || field.type === 'List'"  v-model="field.size" placeholder="Размерность">
                    <input type="text" v-if="field.type === 'Integer'"  v-model="field.value" placeholder="Значение">
                </li>
                <ul><el-inpt-group v-for="child in fields.value" :style="{marginLeft: field.left+'px'}" :key="child.name" :item="child"></el-inpt-group></ul>
            </ul>
    </script>
</head>
<body>
<div class="container">
            <h1 class="font-italic text-warning">TDGT Web Client</h1>
           
                <button id="add-field" class="btn btn-sm btn-warning" @click="addNewField">Create field</button>
                <button id="show-json" class="btn btn-sm btn-warning" @click="showJson">Show JSON</button>
                <el-inpt-group :item="fields"></el-inpt-group>

            </div>
    </div>

1 个答案:

答案 0 :(得分:0)

确实递归是您的解决方案。

当您看不到如何正确组织代码时,通常意味着您没有将代码划分为足够多的组件。

举个简单的例子,只需要创建一个组件,将一个item作为属性,然后当这个item作为子item时调用自己。

鉴于此示例结构:

[
  {
     name: 'Todo 1'
  },
  {
     name: 'Todo 2',
     items: [
       {
          name: 'Todo 2.1'
       },
       {
          name: 'Todo 2.2'
       }  
     ],
  },
  {
     name: 'Todo 3',
     items: []

  },
]
<template>
   <div>
      <article v-for="subTodos of todo.items" :key="subTodos.name"> 
          <h1>{{ subTodos.name }}</h1>
          <Todo :todo="subTodos" />
      </article>
   </div>
</template>

<script>
export default {
  name: 'Todo',
  props: {
    todo: { type: Object, required: true }
  }
}
</script>
<template>
   <Todo :todo="firstItem" />
</template>

<script>
export default {
   data () {
     return {
       firstItem: { name: 'First todo', items: nestedTodos }
     }
   }
}
</script>

这里,只要 todo.items 不是空数组,它就会创建一个 <Todo> 组件,只要它们本身有项目,它就会自己创建更多的 <Todo> 元素...< /p>