基于 Vue JS 中的选择下拉列表自动填充输入

fra*_*urt 7 javascript vue.js vuejs3

我正在寻找如何在 vue js 中自动填充输入的解决方案。我有一个表格,其包括输入类型文本,选择下拉,数量等我的要被选择的选择下拉时,那么数量vCPUvRAM以及Storage Capacity将被自动根据所选择的填充值Server Flavor

我试过选择Flavor Server 的Flavor 1options,vCPU马上填4,vRAM填2,存储容量填10,但是数量没有出现。

在此处输入图片说明

但在价格估算中,数字是正确的,即 vCPU (4)、vRAM (2)、存储容量 (10)

在此处输入图片说明

我很困惑,把if条件中<base-quantity>@updateQuantity自定义事件或v-if属性。这里有没有人可以帮我解决这个问题?

完整的源代码在这个codesandbox => https://codesandbox.io/s/suspicious-almeida-rjyy9

精简版

<template>
  <div class="container">
    <h2 class="font-size-26 txt-secondary">Deka Flexi</h2>
    <div class="row">
      <div class="col-12">
        <form @submit.prevent="submitFormLite">
          <div class="form-group form-group--border">
            <label class="font-size-22 txt-secondary txt-semibold">Commitment Type</label>
            <select name="commitment" id="" class="select-custom" v-model="selectedCommitTypeLite">
                <option v-for="ctl in commitTypeLite" :key="ctl.name" :value="ctl.value">{{ ctl.name }}</option>
            </select>
          </div>
          <div class="form-group form-group--border">
            <label class="font-size-22 txt-secondary txt-semibold">Server Name</label>
            <input type="text" name="name" class="custom-input" v-model="serverNameLite" />
          </div>
          <div class="form-group form-group--border">
            <label class="font-size-22 txt-secondary txt-semibold">Server Flavor</label>
              <select name="storage-type" id="" class="select-custom" v-model="selectedServerFlavorLite">
                <option v-for="sfl in serverFlavorLite" :key="sfl.name" :value="sfl.value">{{ sfl.name }}</option>
              </select>
          </div>
          <h6 class="font-size-22 txt-secondary txt-semibold">
              Components
          </h6>
          <div class="row form-group--border">
            <div class="col-md-6">
              <div class="form-group text-center">
                <div class="font-size-18 txt-secondary">vCPU (GHz)</div>
                <base-quantity @updateQuantity="updateCpuLite"></base-quantity>
              </div>
            </div>
            <div class="col-md-6">
              <div class="form-group text-center">
                <div class="font-size-18 txt-secondary">vRAM (GB)</div>
                <base-quantity @updateQuantity="updateRamLite"></base-quantity>
              </div>
            </div>
            <div class="col-md-6">
              <div class="form-group text-center">
                <label class="font-size-18 txt-secondary">Storage Type</label>
                <select name="storage-type" id="" class="select-custom" v-model="selectedStorageTypeLite">
                   <option v-for="stl in storageTypeLite" :key="stl.name" :value="stl.value">{{ stl.name }}</option>
                </select>
              </div>
            </div>
            <div class="col-md-6">
              <div class="form-group text-center">
                <div class="font-size-18 txt-secondary">Storage Capacity (GB)</div>
                <base-quantity @updateQuantity="updateCapacityLite" v-model="updateCapacityLite"></base-quantity>
              </div>
            </div>
          </div>
          <div class="row pt-4">
            <div class="col-md-6">
              <div class="form-group text-center">
                <label class="font-size-18 txt-secondary">Public IP</label>
                <select name="public-ip" id="" class="select-custom" v-model="selectedPublicIpLite">
                   <option v-for="pil in publicIpLite" :key="pil.name" :value="pil.value">{{ pil.name }}</option>
                </select>
              </div>
            </div>
            <div class="col-md-6">
              <div class="form-group text-center">
                <label class="font-size-18 txt-secondary">OS Type</label>
                <select name="os-lite" id="" class="select-custom" v-model="selectedOsLite">
                   <option v-for="ol in osLite" :key="ol.name" :value="ol.value">{{ ol.name }}</option>
                </select>
              </div>
            </div>
            <div class="col-md-6">
              <div class="form-group text-center">
                <div class="font-size-18 txt-secondary">Quantity</div>
                <base-quantity @updateQuantity="updateQuantityLite"></base-quantity>
              </div>
            </div>
          </div>
          <div class="form-group mt-4 text-center">
            <button class="button button__add" @click="addToCart">Submit</button>
          </div>
        </form>
      </div>
    </div>
  </div>
</template>

<script>
import BaseQuantity from "../base/BaseQuantity.vue";
export default {
  components: {
    BaseQuantity,
  },
  data() {
    return {
      serverNameLite: '',
      storageTypeLite: [
        {
          name: "Storage Type 1",
          value: 100
        },
        {
          name: "Storage Type 2",
          value: 120
        }
      ],
      publicIpLite: [
        {
          name: "Yes",
          value: 120
        },
        {
          name: "No",
          value: 20
        }
      ],
      osLite: [
        {
          name: "OS 1",
          value: 80
        },
        {
          name: "OS 2",
          value: 100
        },
        {
          name: "OS 3",
          value: 120
        }
      ],
      serverFlavorLite: [
        {
          name: "Flavor 1",
          value: "flavor-1"
        },
        {
          name: "Flavor 2",
          value: "flavor-2"
        },
        {
          name: "Flavor 3",
          value: "flavor-3"
        }
      ],
      commitTypeLite: [
        {
          name: "Commitment Type 1",
          value: 80
        },
        {
          name: "Commitment Type 2",
          value: 100
        },
        {
          name: "Commitment Type 3",
          value: 120
        }
      ],
      selectedStorageTypeLite: "",
      selectedPublicIpLite: "",
      selectedOsLite: "",
      selectedCommitTypeLite: "",
      selectedServerFlavorLite:""
    };
  },
  watch: {
    serverNameLite: function() {
      this.$store.commit('setServerNameLite', this.serverNameLite);
    },
    selectedStorageTypeLite: function() {
      let storageTypeLite = this.storageTypeLite.find((storageTypeLite) => storageTypeLite.value == this.selectedStorageTypeLite);
      this.$store.commit('setStorageTypeLite', storageTypeLite);
    },
    selectedPublicIpLite: function() {
      let publicIpLite = this.publicIpLite.find((publicIpLite) => publicIpLite.value == this.selectedPublicIpLite);
      this.$store.commit('setPublicIpLite', publicIpLite);
      console.log(publicIpLite);
    },
    selectedOsLite: function() {
      let osLite = this.osLite.find((osLite) => osLite.value == this.selectedOsLite);
      this.$store.commit('setOsLite', osLite);
    },
    selectedCommitTypeLite: function() {
      let commitTypeLite = this.commitTypeLite.find((commitTypeLite) => commitTypeLite.value == this.selectedCommitTypeLite);
      this.$store.commit('setCommitTypeLite', commitTypeLite);
    },
    selectedServerFlavorLite: function() {
      let serverFlavorLite = this.serverFlavorLite.find((serverFlavorLite) => serverFlavorLite.value == this.selectedServerFlavorLite);
      this.$store.commit('setServerFlavorLite', serverFlavorLite);

      if(this.selectedServerFlavorLite == "flavor-1"){
          this.updateCpuLite(4);
          this.updateRamLite(2);
          this.updateCapacityLite(10);
      }
    },
  },
  methods: {
    async addToCart() {
        let isLiteEmpty = await this.$store.dispatch('isLiteEmpty');
      if(!isLiteEmpty) {
        this.$store.commit('calculateLiteCost');
        this.$store.commit('setLite', this.$store.getters.getLiteState);
        this.$store.commit('calculatePrice');
      }
    },
    updateCpuLite(val) {
      this.$store.commit('setCpuLite', {qty: val, value: 100});
      console.log(val);
    },
    updateRamLite(val) {
      this.$store.commit('setRamLite', {qty: val, value: 100});
       console.log(val);
    },
    updateCapacityLite(val) {
      this.$store.commit('setCapacityLite', {qty: val, value: 100});
       console.log(val);
    },
    updateQuantityLite(val) {
      this.$store.commit('setQuantityLite', {qty: val, value: 100});
       console.log(val);
    },
  },
};
</script>

Run Code Online (Sandbox Code Playgroud)
selectedServerFlavorLite: function() {
      let serverFlavorLite = this.serverFlavorLite.find((serverFlavorLite) => serverFlavorLite.value == this.selectedServerFlavorLite);
      this.$store.commit('setServerFlavorLite', serverFlavorLite);

      if(this.selectedServerFlavorLite == "flavor-1"){
          this.updateCpuLite(4);
          this.updateRamLite(2);
          this.updateCapacityLite(10);
      }
    },
Run Code Online (Sandbox Code Playgroud)

基本数量.vue

<template>
    <div class="quantity" :class="disabled ? 'quantity__untoggle' : 'quantity__toggle'">
        <button type="button" @click="decrement" class="btn quantity__decrement" :disabled="disabled">-</button>
        <input type="text" class="quantity__value" :value="quantity" :disabled="disabled" readonly>
        <button type="button" @click="increment" class="btn quantity__increment" :disabled="disabled">+</button>
    </div>
</template>

<script>
export default {
    props : ['disabled'],
    data(){
        return{
            quantity: null
        }
    },
    watch:{
        quantity :function(val){
            this.$emit('updateQuantity',val);
        }
    },
    methods :{
        increment () {
            this.quantity++
        },
        decrement () {
            if(this.quantity === 0) {
                alert('Negative quantity not allowed')
            } else {
                this.quantity--
            }
        }
    }
}
</script>

Run Code Online (Sandbox Code Playgroud)

And*_*pov 5

有多种方式,但这一切都取决于您的数据如何通过组件存储和连接。

让我们从BaseQuantity.vue

data() {
  return {
    quantity: 0 // you have a local saved state of the quantity
  }
},
methods: {
  increment() {
    this.quantity++ // when user hits something, you increment the LOCAL state
  },
}
watch: {
  quantity: function(val) { // when the LOCAL value updates
    this.$emit('updateQuantity', val); // you emit event it has been updated
  }
}
Run Code Online (Sandbox Code Playgroud)

基本上,您的每个 Base Quantity 组件都定义了它的状态(从 开始0),然后跟踪它自己更新该状态的操作。

您使用这些组件,例如

<base-quantity @updateQuantity="updateServer"

并且该方法调用 Vuex 来存储新值(从组件中获取,等于它的内部状态):

updateServer(val) {
  this.$store.commit('setServer', {qty: val, value: 100});
}
Run Code Online (Sandbox Code Playgroud)
  1. 您的第一个问题是,每个 Base Quantity 组件都定义了自己的初始状态,这是内部且独立的。目前,没有真正的方法可以告诉其中任何一个“你的价值是 X”,恰恰相反——他们告诉父母“我已经更新了我的价值”。

    为此,您必须以某种方式设置初始值。非常基本的方法是将初始值传递给组件:

    props : ['disabled', 'initialValue'],
    data(){
      return {
        quantity: this.initialValue
      }
    },
    
    Run Code Online (Sandbox Code Playgroud)
  2. 现在的问题二是,您不仅需要初始值,还需要在用户选择下拉选项时从外部设置该值。但您还希望跟踪组件的手动更新。因此,您需要对值进行双向绑定(设置和更新)。这就是v-model派上用场的地方。这是一篇很好的文章,解释了它以前是如何工作的,现在是如何工作的:https : //v3.vuejs.org/guide/migration/v-model.html#overview基本上你会这样使用它:

    <base-quantity v-model="serverQuantity" />
    
    <!-- would be shorthand for: -->
    
    <base-quantity
      :modelValue="serverQuantity"
      @update:modelValue="serverQuantity= $event"
    />
    
    Run Code Online (Sandbox Code Playgroud)
  3. 您不会将数据存储在 Calculator 组件中——而是将其存储在 Vuex 中。现在这是您有很多解决方案的部分,您需要小心设计数据流。我会选择最简单的:

    • 使用商店干将指导基地数量的值是多少:<base-quantity :value="$store.getters.serverQuantity" />。这是一个反应性属性,当商店更新其服务器数量值时会更新。如果您没有 getter,则可以使用 state 代替,但不建议这样做。
    • 删除数量的局部变量,只需使用传递的属性: <input :value="value" />
    • 更新时(单击按钮),发出具有新值的事件,而不在本地更新它increment() { this.$emit('updateQuantity', this.value + 1)
    • 在您的处理程序中,提交截至现在的更新

  1. 为了处理下拉选择,如果您使用上述方法,您只需要等待用户输入(下拉选择)并使用所有需要的字段填充商店。由于它们被传递到每个组件,该值将被自动填充:

    watch: {
      selectedPackage: function() {
        let pack = this.storagePackage.find((pack) => pack.value == this.selectedPackage);
        this.$store.commit('setPackage', pack);
        // here you should somehow map the pack to the values you'd like to populate
        // let's say package "One" (value: 30) means you'd have 8 vRAM, then:
        this.updateRam(package.ram);
        // this would call this.$store.commit('setRam', { qty: 8, value: 100 });
    
        this.updateCapacity(100);
        this.updateCpu(5);
        // all the other fields you'd like to update, with the specific values this PACK has (I haven't seen any map for plan -> values)
      },
    }
    
    Run Code Online (Sandbox Code Playgroud)

    ps我不完全确定你为什么qty: val, value: 100到处存储,但你可能有一些原因。

通过这种方法,您将拥有关于数据的单一真实来源。和单独的组件,只是说“我希望这个值(无论它是什么)增加或减少”。因此该组件与任何对修改和存储的真实业务逻辑以及属性名称的了解完全隔离。父级是双向处理数据的人 - 首先将其发送到每个组件,其次 - 它处理用户操作,然后将其提交到 Vuex 存储(单点真实性)。