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)。如果datatypestring,那么将显示一个简单的文本字段。但是,如果datatypecomplex,则应显示另一个按钮,并且再次单击该按钮时,将显示相同的模态字段并继续该过程。所以基于此创建的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

由于您的 extensioncomplex 时将是另一个数组,因此您可以将其作为道具直接传递到此 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>

请注意,我在更改输入文本时从子 NodeComponents 发出自定义事件,以便父可以在其 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 向用户显示相同的对象的主要内容,如果未能解决你的问题,请参考以下文章

AngularJS ng-repeat 通过复杂和动态的 JSON 数组

bootstrap-vue中基于json文件动态生成元素

动态 linq:创建生成 JSON 结果的扩展方法

从 vuejs 表单数据创建 JSON 对象

vuejs 返回json数据怎么循环渲染到页面

创建动态 html 并在其中显示 json 值