基于VueJS中的选择下拉列表自动填充输入
我正在寻找如何在 vue js 中自动填充输入的解决方案。我有一个表格,其包括输入类型文本,选择下拉,数量等我的要被选择的选择下拉时,那么数量vCPU,vRAM以及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>
<h2>Deka Flexi</h2>
<div>
<div>
<form @submit.prevent="submitFormLite">
<div>
<label>Commitment Type</label>
<select name="commitment" v-model="selectedCommitTypeLite">
<option v-for="ctl in commitTypeLite" :key="ctl.name" :value="ctl.value">{{ ctl.name }}</option>
</select>
</div>
<div>
<label>Server Name</label>
<input type="text" name="name" v-model="serverNameLite" />
</div>
<div>
<label>Server Flavor</label>
<select name="storage-type" v-model="selectedServerFlavorLite">
<option v-for="sfl in serverFlavorLite" :key="sfl.name" :value="sfl.value">{{ sfl.name }}</option>
</select>
</div>
<h6>
Components
</h6>
<div>
<div>
<div>
<div>vCPU (GHz)</div>
<base-quantity @updateQuantity="updateCpuLite"></base-quantity>
</div>
</div>
<div>
<div>
<div>vRAM (GB)</div>
<base-quantity @updateQuantity="updateRamLite"></base-quantity>
</div>
</div>
<div>
<div>
<label>Storage Type</label>
<select name="storage-type" v-model="selectedStorageTypeLite">
<option v-for="stl in storageTypeLite" :key="stl.name" :value="stl.value">{{ stl.name }}</option>
</select>
</div>
</div>
<div>
<div>
<div>Storage Capacity (GB)</div>
<base-quantity @updateQuantity="updateCapacityLite" v-model="updateCapacityLite"></base-quantity>
</div>
</div>
</div>
<div>
<div>
<div>
<label>Public IP</label>
<select name="public-ip" v-model="selectedPublicIpLite">
<option v-for="pil in publicIpLite" :key="pil.name" :value="pil.value">{{ pil.name }}</option>
</select>
</div>
</div>
<div>
<div>
<label>OS Type</label>
<select name="os-lite" v-model="selectedOsLite">
<option v-for="ol in osLite" :key="ol.name" :value="ol.value">{{ ol.name }}</option>
</select>
</div>
</div>
<div>
<div>
<div>Quantity</div>
<base-quantity @updateQuantity="updateQuantityLite"></base-quantity>
</div>
</div>
</div>
<div>
<button @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);
}
},
基本数量.vue
<template>
<div :class="disabled ? 'quantity__untoggle' : 'quantity__toggle'">
<button type="button" @click="decrement" :disabled="disabled">-</button>
<input type="text" :value="quantity" :disabled="disabled" readonly>
<button type="button" @click="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>
回答
有多种方式,但这一切都取决于您的数据如何通过组件存储和连接。
让我们从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),然后跟踪它自己更新该状态的操作。
您使用这些组件,例如
<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 中。现在这是您有很多解决方案的部分,您需要小心设计数据流。我会选择最简单的:
- 使用商店干将指导基地数量的值是多少:
<base-quantity :value="$store.getters.serverQuantity" />。这是一个反应性属性,当商店更新其服务器数量值时会更新。如果您没有 getter,则可以使用 state 代替,但不建议这样做。 - 删除数量的局部变量,只需使用传递的属性:
<input :value="value" /> - 更新时(单击按钮),发出具有新值的事件,而不在本地更新它:
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) }, }ps我不完全确定你为什么
qty: val, value: 100到处存储,但你可能有一些原因。
通过这种方法,您将拥有关于数据的单一真实来源。和单独的组件,只是说“我希望这个值(无论它是什么)增加或减少”。因此该组件与任何对修改和存储的真实业务逻辑以及属性名称的了解完全隔离。父级是双向处理数据的人 - 首先将其发送到每个组件,其次 - 它处理用户操作,然后将其提交到 Vuex 存储(单点真实性)。