Vuejs 和 HTML 动态创建一个复杂的 JSON 对象并使用 V-for 向用户显示该对象
Vuejs and HTML creating a complex JSON Object dynamically and displaying the same to user using V-for
我正在开发一个 Vuejs
应用程序,我在其中有一个字段。对于此字段,用户可以提供值,此字段会根据用户提供的值动态扩展。
字段名称是extensions
,最初会显示一个Add Extension
按钮。单击按钮,将显示一个 bootstrap 模态,其中包含 3 个字段:namespace (text), localname (text), datatype(dropdown: string/complex)
。如果 datatype
是 string
,那么将显示一个简单的文本字段。但是,如果 datatype
是 complex
,则应显示另一个按钮,再次单击该按钮会显示带有字段的相同模式,并且该过程会继续。所以在此基础上创建的JSON会横向和纵向展开
我能够完成第一次迭代并在前端向用户显示元素。但是,对于进一步的迭代,我不明白如何使用递归方法来实现它。因为我不知道用户可能会创建多少次扩展,所以我需要一种动态执行此操作的方法。
有人可以帮助我如何使用 Vuejs 创建和显示水平和垂直扩展的 JSON 数组吗?
以下是我目前的代码:
<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"
width="100%"
: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 并在前端显示。
要递归显示数据,需要使用递归组件。
将您的 v-for
代码抽象到另一个组件文件中(我们称之为 NodeComponent.vue
)。将您的 extensionList
传递给此组件,然后在此组件内,为每个类型为 complex
.
的每个 extension
添加另一个 NodeComponent
如果你的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
发出自定义事件,以便父可以在其 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 商店可能是值得的,您可以在其中拥有全局扩展列表并为其定义突变。
我正在开发一个 Vuejs
应用程序,我在其中有一个字段。对于此字段,用户可以提供值,此字段会根据用户提供的值动态扩展。
字段名称是extensions
,最初会显示一个Add Extension
按钮。单击按钮,将显示一个 bootstrap 模态,其中包含 3 个字段:namespace (text), localname (text), datatype(dropdown: string/complex)
。如果 datatype
是 string
,那么将显示一个简单的文本字段。但是,如果 datatype
是 complex
,则应显示另一个按钮,再次单击该按钮会显示带有字段的相同模式,并且该过程会继续。所以在此基础上创建的JSON会横向和纵向展开
我能够完成第一次迭代并在前端向用户显示元素。但是,对于进一步的迭代,我不明白如何使用递归方法来实现它。因为我不知道用户可能会创建多少次扩展,所以我需要一种动态执行此操作的方法。
有人可以帮助我如何使用 Vuejs 创建和显示水平和垂直扩展的 JSON 数组吗?
以下是我目前的代码:
<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"
width="100%"
: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 并在前端显示。
要递归显示数据,需要使用递归组件。
将您的 v-for
代码抽象到另一个组件文件中(我们称之为 NodeComponent.vue
)。将您的 extensionList
传递给此组件,然后在此组件内,为每个类型为 complex
.
extension
添加另一个 NodeComponent
如果你的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
发出自定义事件,以便父可以在其 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 商店可能是值得的,您可以在其中拥有全局扩展列表并为其定义突变。