Vue如何实现未知深度的动态嵌套数组对象元素渲染
Vue 动态嵌套元素递归渲染方案
报错原因说明
- 类型校验失败:你定义的
el-inpt-group组件要求item属性为Object类型,但根组件传入的fields是数组,触发类型不匹配报错 - 变量未定义:递归组件模板内直接使用了仅在根实例声明的
fields和createChildElement,组件内部没有对应定义,触发未定义错误
修复逻辑
- 调整递归组件职责:单个组件仅负责渲染单条字段配置,而非整个字段数组
- 递归判断:组件内部如果检测到当前字段类型为List/Map且存在子元素数组
value,则循环子元素递归调用自身 - 方法下沉:将创建子元素的逻辑放到递归组件内部,利用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
相关产品推荐
相关产品推荐

