Vuejs 和 HTML 动态创建复杂的 JSON 对象并使用 V-for 向用户显示相同的对象
Posted
技术标签:
【中文标题】Vuejs 和 HTML 动态创建复杂的 JSON 对象并使用 V-for 向用户显示相同的对象【英文标题】:Vuejs and HTML creating a complex JSON Object dynamically and displaying the same to user using V-for 【发布时间】:2021-11-09 22:25:08 【问题描述】:我正在开发一个Vuejs
应用程序,其中我有一个字段。对于此字段,用户可以提供值,并且此字段会根据用户提供的值动态扩展。
字段名称是extensions
,最初会显示一个Add Extension
按钮。单击按钮后,将显示一个引导模式,其中包含 3 个字段:namespace (text), localname (text), datatype(dropdown: string/complex)
。如果datatype
是string
,那么将显示一个简单的文本字段。但是,如果datatype
是complex
,则应显示另一个按钮,并且再次单击该按钮时,将显示相同的模态字段并继续该过程。所以基于此创建的JSON会横向纵向扩展。
我能够完成第一次迭代并在前端向用户显示元素。但是,对于进一步的迭代,我不了解如何使用递归方法来实现它。由于我不知道用户可能会创建多少次扩展,因此我需要一种动态执行此操作的方法。
有人可以帮我如何使用水平和垂直扩展的 Vuejs 创建和显示 JSONarray 吗?
以下是我目前的代码:
<template>
<div class="container-fluid">
<div class="row">
<div class="col-md-3">
<span>Extensions</span>
<button class="form-control" @click="createExtensions()">
Add Another
</button>
</div>
</div>
<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" @input="AddExtensionText($event,extension.ID)">
<button v-if="extension.dataType == 'complex'" @click="AddComplextExtension(extension.ID)">
Add another
</button>
</div>
<b-modal
id="Extension"
title="Add Another Element"
size="lg"
:visible="showModal"
>
<b-form id="AddExtension" @submit.prevent="submitExtension">
<div class="form-group">
<label for="message-text" class="col-form-label">Namespace URI:</label>
<input
v-model="extension.namespace"
type="text"
class="form-control"
required
>
</div>
<div class="form-group">
<label for="message-text" class="col-form-label">Local Name:</label>
<input
v-model="extension.localName"
type="text"
class="form-control"
required
>
</div>
<div class="form-group">
<label for="AddExtensionDataType" class="col-form-label">Data Type:</label>
<b-form-select v-model="extension.dataType" class="form-control">
<b-form-select-option value="string">
String
</b-form-select-option>
<b-form-select-option value="complex">
Complex
</b-form-select-option>
</b-form-select>
</div>
</b-form>
<template #modal-footer=" cancel ">
<b-btn @click="cancel">
Cancel
</b-btn>
<b-btn variant="primary" type="submit" form="AddExtension">
OK
</b-btn>
</template>
</b-modal>
</div>
</template>
<script>
export default
data ()
return
extensionList: [],
extensionCount: 0,
extension:
namespace: '',
localName: '',
dataType: 'string'
,
showModal: false
,
methods:
// Method to create extensions and add
createExtensions ()
this.showModal = true
,
// Function to submit the each extension
submitExtension ()
this.showModal = false
const extensionObj =
extensionObj.ID = this.extensionCount
extensionObj.namespace = this.extension.namespace
extensionObj.localName = this.extension.localName
extensionObj.dataType = this.extension.dataType
this.extensionList.push(extensionObj)
this.extensionCount++
,
// On addition of the input field value update List
AddExtensionText (event, extensionID)
const extension = this.extensionList.filter(ex => ex.ID === extensionID)[0]
if (typeof extension !== 'undefined')
extension.text = (typeof event.target.value !== 'undefined') ? event.target.value : ''
,
// Add complex extension
AddComplextExtension (extensionID)
this.showModal = true
</script>
<style>
</style>
这是我拥有的初始字段:
这就是我想要实现的,一切都是动态创建的,JSON 水平和垂直扩展:
谁能告诉我如何使用 Vuejs 创建这样的动态 JSON 并在前端显示。
【问题讨论】:
试试这个解决方案github.com/jinkin1995/vue-json-edit 【参考方案1】:要递归显示数据,需要用到递归组件。
将您的v-for
代码抽象到另一个组件文件中(我们称之为NodeComponent.vue
)。将您的extensionList
传递给该组件,然后在该组件内,为每个extension
添加另一个NodeComponent
,其类型为complex
。
由于您的 extension
是 complex
时将是另一个数组,因此您可以将其作为道具直接传递到此 NodeComponent
并让递归发挥其魔力。
NodeComponent.vue
<template>
<div>
<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"
@input="$emit('AddExtensionText', $event, id: extension.ID"
/>
<NodeComponent v-if="extention.dataType == 'complex'" :extentionList="extension" @AddExtensionText="AddExtensionText($event)"/>
<button
v-if="extension.dataType == 'complex'"
@click="AddComplextExtension(extension.ID)"
>
Add another
</button>
</div>
</div>
</template>
<script>
export default
props:
extensionList: Array,
extension: Object,
,
methods:
AddComplextExtension(extensionID)
// Emit event on root to show modal, or use this.$bvModal.show('modal-id') or create a dynamic modal, see: https://bootstrap-vue.org/docs/components/modal#message-box-advanced-usage
AddExtensionText( value, id )
const i = this.extensionList.findIndex((el) => el.ID === id);
this.$set(extensionList, i, value);
;
</script>
请注意,我在更改输入文本时从子 NodeComponent
s 发出自定义事件,以便父可以在其 extensionList
数组中进行此更改,使用 this.$set
保持反应性。
编辑:如果你想添加新的节点组件:
您需要有一个包含第一个 NodeComponent 的父组件。在这里,您将定义模态(如果您在 NodeComponent 中定义它,则每个 NodeComponent 都会有一个单独的模态引用。从您的代码来看,您可能正在使用 Bootstrap-Vue,它在显示时会延迟注入模态,所以我不要认为这会对你的性能产生太大影响,但它仍然不像是好的代码。)。您需要在根上发出事件以显示模式。您需要使用此事件发送extensionList
作为有效负载,如下所示:this.$root.emit('showModal', extensionList)
。在您的父组件中,您可以收听事件并显示模式。现在在您的submitExtension
函数中,您可以使用这个extensionList
并将一个新对象推送给它。相应的 NodeComponent 将自行更新,因为数组是通过引用传递的。
this.$root.on('showModal`, (extensionList) =>
this.editExtensionList = extensionList;
showModal = true;
submitExtension()
this.showModal = false
const extensionObj =
extensionObj.ID = this.extensionCount
extensionObj.namespace = this.extension.namespace
extensionObj.localName = this.extension.localName
extensionObj.dataType = this.extension.dataType
this.editExtensionList.push(extensionObj)
this.extensionCount++
总而言之,在这一点上,可能值得投资实现一个 VueX 存储,其中您有一个全局扩展列表并对其定义突变。
【讨论】:
@BATMAN_2008 检查我的更新答案 很酷,您制作了一个沙盒,让事情变得更容易。一会儿我会 fork 它发布一个工作沙箱的链接。 @BATMAN_2008 你非常接近。但是你让它变得比它必须的更复杂。 Here's the working sandbox。如果您想澄清某些事情,请告诉我。 你太棒了,非常感谢你的回复。一切都按预期工作。我已经根据我的应用程序中的更改添加了对文本字段值的修改、删除和捕获。一切似乎都按预期工作。再次感谢您帮助我解决问题。祝你有美好的一天:) 总是很高兴为您提供帮助,也祝您有美好的一天:)以上是关于Vuejs 和 HTML 动态创建复杂的 JSON 对象并使用 V-for 向用户显示相同的对象的主要内容,如果未能解决你的问题,请参考以下文章