VueJS组件动态创建展示复杂嵌套JSON对象的实现问题求助
核心问题分析
现有代码缺少父子层级绑定逻辑,无法区分新增的扩展是根节点还是某个complex类型节点的子节点,同时递归组件的props传参存在类型错误,导致无法嵌套展示。以下是完整修改方案:
1. 修改Vuex Store 逻辑
新增currentParentId字段记录当前新增节点的父ID,调整新增逻辑自动绑定父子关系,complex类型节点默认初始化children数组:
export const state = () => ({ extensionID: 0, extensionList: [], showModal: false, // 新增:当前要添加的子节点所属父节点ID,根节点为null currentParentId: null }) export const mutations = { toggleExtensionModal (state, parentId = null) { state.showModal = !state.showModal // 打开弹窗时记录父ID,关闭时重置 if (state.showModal) { state.currentParentId = parentId } else { state.currentParentId = null } }, addExtension (state, extension) { extension.ID = state.extensionID // complex类型默认添加children数组用于存子节点 if (extension.dataType === 'complex') { extension.children = [] } // 判断是根节点还是子节点 if (state.currentParentId === null) { state.extensionList.push(extension) } else { // 递归查找父节点 const findParent = (list) => { for (let item of list) { if (item.ID === state.currentParentId) return item if (item.children) { const res = findParent(item.children) if (res) return res } } return null } const parent = findParent(state.extensionList) if (parent) parent.children.push(extension) } state.extensionID++ } }
2. 修正ExtensionComponent递归组件
修复props传参错误,调整新增子节点的触发逻辑:
<template> <div style="margin-left: 20px;"> <div v-for="extension in extensionList" :key="extension.ID" class="form-inline" > <span>{{ extension.namespace + ":" + extension.localName }}</span> <input v-if="extension.dataType == 'string'" type="text" v-model="extension.value" > <!-- 修正:传children数组给递归组件 --> <ExtensionComponent v-if="extension.dataType == 'complex'" :extension-list="extension.children" /> <button v-if="extension.dataType == 'complex'" @click="AddComplexExtension(extension.ID)" style="margin-left: 10px;" > Add another </button> </div> </div> </template> <script> import ExtensionComponent from '@/components/ExtensionComponent.vue' export default { name: 'ExtensionComponent', components: { ExtensionComponent }, props: { extensionList: { type: Array, default: () => [] } }, methods: { AddComplexExtension (parentId) { // 打开弹窗时传入当前父节点ID this.$store.commit('toggleExtensionModal', parentId) } } } </script>
3. 调整Test.vue根页面逻辑
修正组件导入位置:
<template> <div> <span>Extensions</span> <button class="btn btn-primary" @click="createExtensions" style="margin-left: 10px;"> Add Extension </button> <ExtensionComponent :extension-list="$store.state.extensionList" /> <TestModal v-if="$store.state.showModal" /> </div> </template> <script> import TestModal from '@/components/TestModal.vue' import ExtensionComponent from '@/components/ExtensionComponent.vue' export default { components: { TestModal, ExtensionComponent }, methods: { createExtensions () { // 根节点不传父ID this.$store.commit('toggleExtensionModal') } } } </script>
4. TestModal.vue无需大改,仅需重置表单数据
<script> export default { data () { return { extension: { namespace: '', localName: '', dataType: 'string' } } }, methods: { submitExtension () { // 深拷贝避免引用问题 this.$store.commit('addExtension', JSON.parse(JSON.stringify(this.extension))) this.$store.commit('toggleExtensionModal') // 重置表单 this.extension = { namespace: '', localName: '', dataType: 'string' } } } } </script>
最终效果
生成的JSON结构符合纵横双向扩展要求,示例如下:
[ { "ID": 0, "namespace": "ns1", "localName": "ext1", "dataType": "string", "value": "测试文本" }, { "ID": 1, "namespace": "ns2", "localName": "ext2", "dataType": "complex", "children": [ { "ID": 2, "namespace": "ns3", "localName": "ext3", "dataType": "complex", "children": [ { "ID": 3, "namespace": "ns4", "localName": "ext4", "dataType": "string", "value": "嵌套文本" } ] } ] } ]
内容的提问来源于stack exchange,提问作者BATMAN_2008
相关产品推荐
相关产品推荐

