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

Posted

技术标签:

【中文标题】基于 Vue JS 中的选择下拉菜单自动填充输入【英文标题】:Auto fill input based on select dropdown in Vue JS 【发布时间】:2021-08-05 18:15:09 【问题描述】:

我正在寻找如何在 vue js 中自动填充输入的解决方案。我的表格包括输入类型文本,选择下拉,数量等。我想要选择下拉列表时,然后vCPU,@ 987654327和Storage Capacity将自动填充值根据选中的Server Flavor

我尝试选择带有Flavor 1选项的Flavor Server,vCPU应该立即填充值4,vRAM应该填充值2,存储容量应该填充值10。但是数量没有出现。

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

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

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

Lite.vue

<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>

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);
      
    ,

BaseQuantity.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>

【问题讨论】:

嗨,尝试在输入字段中使用v-model &lt;base-quantity&gt;中的输入字段? 【参考方案1】:

您可以使用 v-model 设置值,但这是一个不同的场景,其中值基于选定的事件。所以我找到了这个解决方案,您可以在其中创建一个在自定义模式下设置值的函数

试试这个:

setValues: function () 
      this.specifications === this.specifications[1]
        ? (this.os = this.os[0].name)
        : (this.os = '');

您也可以传入其他数据库、存储类型、防火墙值。

【讨论】:

【参考方案2】:

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

让我们从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
  

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

您使用这些组件,例如

&lt;base-quantity @updateQuantity="updateServer"

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

updateServer(val) 
  this.$store.commit('setServer', qty: val, value: 100);


    您的第一个问题是这些 Base Quantity 组件中的每一个都定义了自己的初始状态,该状态是内部独立的。目前,没有真正的方法可以告诉任何人“你的价​​值是 X”,恰恰相反——他们告诉父母“我已经更新了我的价值”。

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

    props : ['disabled', 'initialValue'],
    data()
      return 
        quantity: this.initialValue
      
    ,
    

    现在的问题二是,您不仅需要初始值,还需要在用户选择下拉选项时从外部设置该值。但是您还想跟踪组件的手动更新。因此,您需要值的双向绑定(设置和更新)。这就是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"
    />
    

    您不会将数据存储在 Calculator 组件中 - 您将其存储在 Vuex 中。现在这是您有很多解决方案的部分,您需要小心设计数据流的方式。我会选择最简单的:

    使用 store getter 来指示 Base Quantity 的值是多少:&lt;base-quantity :value="$store.getters.serverQuantity" /&gt;。这是一个 reactive 属性,将在商店更新其服务器数量值时更新。如果您没有 getter,您可以改用 state,但不建议这样做。 删除数量的局部变量,只使用传递的属性:&lt;input :value="value" /&gt; 更新时(单击按钮),发出具有新值的事件而不在本地更新它increment() this.$emit('updateQuantity', this.value + 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)
      ,
    
    

    附言我不完全确定您为什么将qty: val, value: 100 存储在任何地方,但您可能有一些原因。

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

【讨论】:

这就是我遇到的&lt;base-quantity&gt; 问题。调节方法如果(例如:Option 1下拉选择,那么vCPUvRAMquantity的值会自动填充。例如,如果我选择Option 1,则vCPU的值用1填充,vRAM的值用2填充,quantity的值用10填充)? 如果您使用上面的示例,base-quantity 中的值将是来自 Vuex 商店的值。因此,当用户从下拉列表中选择某些内容时 - 只需像现在对每个单独更新所做的那样填充(提交)所有必要的值来处理它。它们将自动填充到字段中,因为它们与商店数据一起使用。单点真相:) 按照您的解释,我已经在代码部分更改了上面的帖子,并且我已经更改了我的代码沙箱中的代码,但它仍然无法正常工作。我的实施有问题吗? @安德烈波波夫 在选定的包中,我尝试在价格估算卡中添加这个if(this.storagePackage == "package-1") this.updateRam(4); this.updateCpu(2); this.updateCapacity(100); ,值为真(4,2,100)但为什么在数量输入中没有显示该值? 您缺少将值发送到 BaseQuantity 的部分。此外,您没有正确更新您的商店(storagePackage 是一个对象,它永远不等于package-)。这是 CPU 的一个工作示例:codesandbox.io/s/charming-shape-wsz17

以上是关于基于 Vue JS 中的选择下拉菜单自动填充输入的主要内容,如果未能解决你的问题,请参考以下文章

jquery ui 选择菜单自动填充

根据第一个选择动态填充第二个下拉菜单

根据另一个下拉列表中的选择填充一个下拉列表,然后重定向

根据下拉值自动填充文本框

Laravel-从下拉列表中选择值后自动填充输入

如何使用Google自动完成和Vue js来自动填写地址?