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)。如果 datatypestring,那么将显示一个简单的文本字段。但是,如果 datatypecomplex,则应显示另一个按钮,再次单击该按钮会显示带有字段的相同模式,并且该过程会继续。所以在此基础上创建的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 商店可能是值得的,您可以在其中拥有全局扩展列表并为其定义突变。