You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Vue如何实现未知深度的动态嵌套数组对象元素渲染

Vue 动态嵌套元素递归渲染方案

报错原因说明

  • 类型校验失败:你定义的el-inpt-group组件要求item属性为Object类型,但根组件传入的fields是数组,触发类型不匹配报错
  • 变量未定义:递归组件模板内直接使用了仅在根实例声明的fields和createChildElement,组件内部没有对应定义,触发未定义错误

修复逻辑

  1. 调整递归组件职责:单个组件仅负责渲染单条字段配置,而非整个字段数组
  2. 递归判断:组件内部如果检测到当前字段类型为List/Map且存在子元素数组value,则循环子元素递归调用自身
  3. 方法下沉:将创建子元素的逻辑放到递归组件内部,利用Vue对象引用传递的特性直接修改字段数据,无需额外事件通信

完整可运行代码

JS 代码

Vue.component("el-inpt-group", {
  template: "#item-template",
  props: {
    field: {
      type: Object,
      required: true
    }
  },
  methods: {
    createChildElement() {
      if (this.field.type === "List" || this.field.type === "Map") {
        if (!Array.isArray(this.field.value)) {
          this.$set(this.field, "value", []);
        }
        this.field.value.push({
          name: '',
          type: '',
          left: this.field.left + 20,
          method: '',
          size: '',
          value: ''
        });
      }
    }
  }
})

var app = new Vue({
  el: '.container',
  data: {
    modelname: '',
    fields: []
  },
  methods: {
    addNewField() {
      this.fields.push({
        name: '',
        left: 0,
        type: '',
        method: '',
        size: '',
        value: ''
      })
    },
    showJson() {
      alert(JSON.stringify(this.fields, null, 2));
    }
  }
})

HTML 代码

<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>

<script type="text/x-template" id="item-template">
  <li :style="{marginLeft: field.left + 'px'}">
    <input type="text" v-model="field.name" placeholder="字段名">
    <select v-model="field.type" v-on:change="createChildElement" aria-label="选择字段类型">
      <option selected value="">字段类型</option>
      <option value="List">列表</option>
      <option value="Map">映射</option>
      <option value="Integer">整数</option>
    </select>
    <select v-model="field.method" v-if="field.type === 'Map' || field.type === 'List'" aria-label="生成方法">
      <option selected value="">值类型</option>
      <option value="Static">静态</option>
      <option value="Random">随机</option>
      <option value="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="值">
    <ul v-if="Array.isArray(field.value) && field.value.length">
      <el-inpt-group 
        v-for="(child, index) in field.value" 
        :key="index"
        :field="child"
      ></el-inpt-group>
    </ul>
  </li>
</script>

<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">新增字段</button>
  <button id="show-json" class="btn btn-sm btn-warning" @click="showJson">查看JSON</button>
  <ul>
    <el-inpt-group 
      v-for="(field, index) in fields" 
      :key="index"
      :field="field"
    ></el-inpt-group>
  </ul>
</div>

功能验证

点击「新增字段」创建根级字段,选择「列表/映射」类型会自动生成子级字段,子级字段选择对应类型还可以继续生成下一级,缩进自动累加20px,点击「查看JSON」可导出完整嵌套结构数据。

内容的提问来源于stack exchange,提问作者Igor Belianin

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.14 21:54:06