Vue.js 带有动态单选按钮列表的 v-model
Vue.js v-model with dynamic list of radio buttons
我正在尝试制作一个可重用的 vue 单选按钮组件,它将采用变量名称和一个包含标签和值的对象,然后使用 v-for 呈现单选按钮列表。
我已经成功解决了问题的每一半,但未能将它们结合起来:
- 我可以制作一组绑定到数据模型的单选按钮,其中按钮是在模板中静态定义的,但我不知道如何使列表动态化。这是相关代码:
//component
const Radio = {
template: '#test',
prop: ['value'],
data () {
return {
selected: this.value
}
},
model: {
prop: 'value',
event: 'change'
},
methods: {
handleClickInput (e) {
this.$emit('change', this.selected)
}
}
}
//app
var app2 = new Vue({
el: '#app2',
data: {
door: '',
doorOptions: {
'Yes': 1,
'No': 0,
}
},
components: { Radio, }
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app2">
<radio v-model="door"></radio>
<p>
door = {{door}}
</p>
</div>
<template id="test">
<div>
<input type="radio" value="0" v-model="selected" @change="handleClickInput">0
<input type="radio" value="1" v-model="selected" @change="handleClickInput">1
</div>
</template>
- 我可以根据 "options" 对象制作单选按钮的动态列表,但找不到将它们绑定到数据模型的方法。这是相关代码:
// component
Vue.component('radio-set', {
template: '#radio-set',
props: {
'label-name': '',
'variable': '',
'options': '',
},
methods: {
clicked: function(variable, key, value) {
// none of this is right, it doesn't update the vue data model
window[variable] = value; //assign the new value to the dynamic variable name
selected = value;
this.$emit("click-event", variable) //create the click event for model updating by the parent
}
},
})
//app
var app = new Vue({
el: '#vueApp',
data: {
door:'initial value',
doorOptions: {
'Yes':1,
'No':0,
'Maybe':5,
'A new option':25
},
},
methods: {
buttonClick: function(p1){
console.log(p1+': '+window[p1]); //the variable was assigned inside the child component
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="vueApp">
<radio-set
label-name="Radio button set"
variable="door"
:options="doorOptions"
@click-event="buttonClick"
>door: {{door}}
</radio-set>
</div>
<template id="radio-set">
<div>
<label>{{labelName}}:</label>
<button
type="button"
v-for="(val, key) in options"
@click="clicked(variable, key, val)"
>
{{ key }}
</button>
</div>
</template>
任何人都可以就我如何前进提供一些指导吗?
首先:对于你的选择,有一个数组会更容易。
doorOptions: [
{ key: "Yes", value: 1 },
{ key: "No", value: 0 },
{ key: "Maybe", value: 5 },
{ key: "A new option", value: 25 }
]
};
这样你就可以遍历它了。
在您的自定义组件和您的应用程序之间同步所选值的另一个好方法是使用 v-model。
A tutorial to implement v-model
这样我们就可以创建一个像这样的可重用组件:
<template>
<div>
<label>{{labelName}}:</label>
<button
type="button"
v-for="(val, idx) in options"
:key="idx"
@click="clicked(val)"
>{{ val.key }}</button>
</div>
</template>
<script>
export default {
props: ["value", "options", "labelName"],
methods: {
clicked(val) {
this.$emit("input", val);
}
}
};
</script>
然后像这样使用它
<template>
<div id="app">
<radio-set v-model="selected" label-name="Radio button set" :options="doorOptions"/>
Selected : {{selected.key}}
</div>
</template>
<script>
import RadioSet from "./components/RadioSet";
export default {
name: "App",
components: {
RadioSet
},
data() {
return {
selected: null,
doorOptions: [
{ key: "Yes", value: 1 },
{ key: "No", value: 0 },
{ key: "Maybe", value: 5 },
{ key: "A new option", value: 25 }
]
};
}
};
</script>
如@PierreSaid 所述,您可以阅读更多关于 v-model
在自定义组件上的用法。
这是使用 input[type="radio"]
并将更改事件发回父组件的另一个示例。
// component
Vue.component('radio-set', {
template: '#radio-set',
props: {
'label-name': '',
'value': '',
'options': '',
}
})
//app
var app = new Vue({
el: '#vueApp',
data() {
return {
door: null,
doorOptions: {
'Yes': 1,
'No': 0,
'Maybe': 5,
'A new option': 25
}
};
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.min.js"></script>
<div id="vueApp">
<radio-set label-name="Radio button set" v-model="door" :options="doorOptions"></radio-set>
door: {{door}}
</div>
<template id="radio-set">
<div>
<div>{{labelName}}:</div>
<label v-for="(val, key) in options" :key="val">
<input type="radio"
:name="labelName"
:value="val"
:checked="val == value"
@change="$emit('input', val)">
{{ key }}
</label>
</div>
</template>
在研究和琢磨这些答案的过程中,我想到了以下方法:
- 使用对象数组的首选方法 Vuetify:
new Vue({
el: '#app',
vuetify: new Vuetify(),
data: () => ({
color: {
label: "Choose:",
// Array List
items: [
{ key: 1, value: "Red", color: "red" },
{ key: 2, value: "Green", color: "green" },
{ key: 3, value: "Blue", color: "blue" }
],
selectedItemKey: 2 // Red
}
}),
computed: {
selectedColorItem() {
return this.color.items.find(item => item.key===this.color.selectedItemKey)
}
}
})
<div id="app">
<v-app id="inspire">
<v-container fluid mx-4>
<v-radio-group
:label="color.label"
row
v-model="color.selectedItemKey"
>
<v-radio
:color="item.color"
:key="item.key"
:label="item.value"
:value="item.key"
v-for="(item, index) in color.items"
></v-radio>
</v-radio-group>
Color: <span :class=`${selectedColorItem?.color}--text`>
{{selectedColorItem?.value}}
</span>(key: {{color.selectedItemKey}})
</v-container>
</v-app>
</div>
<link href="https://cdn.jsdelivr.net/npm/@mdi/font@3.x/css/materialdesignicons.min.css" rel="stylesheet"/>
<link href="https://cdn.jsdelivr.net/npm/vuetify@2.0.11/dist/vuetify.min.css" rel="stylesheet"/>
<script src="https://cdn.jsdelivr.net/npm/vue@2.x/dist/vue.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vuetify@2.x/dist/vuetify.js"></script>
根据其他答案之一,我最终得到了 Vue 3。 v-model
的工作方式有一些重大变化,即道具名称。 (https://v3.vuejs.org/guide/migration/v-model.html)
样式是基本的,但我想要一些东西来表明活动选择是什么。
<template>
<div>
<label>{{ labelName }}:</label>
<button
:class="val.key === modelValue ? 'active' : 'inactive'"
type="button"
v-for="(val, idx) in options"
:key="idx"
@click="clicked(val)"
>
{{ val.key }}
</button>
</div>
</template>
<script>
export default {
props: ["modelValue", "options", "labelName"],
methods: {
clicked(val) {
console.log("emitting click", val.key);
this.$emit("update:modelValue", val.key);
},
}
};
</script>
<style scoped>
button {
padding: 10px;
margin: 5px;
}
.active {
background-color: #42b983;
}
.inactive {
background-color: lightgray;
}
</style>
它以同样的方式使用。我只是将一个基本数组映射到 {key, value} 因为这就是我所需要的,但是做一些更明确的事情会很容易。
<template>
<radio-set
label-name="On / Off"
v-model="myValue"
:options="options.radioOptions"
></radio-set>
</template>
<script>
import RadioSet from "./RadioSet.vue";
let options = {
radioOptions: ["on", "off"].map((x) => {
return { key: x, val: x };
}),
};
export default {
name: "MyComponent",
components: {
RadioSet,
},
data: () => {
return {
options,
myValue: "unknown",
};
},
};
</script>
我正在尝试制作一个可重用的 vue 单选按钮组件,它将采用变量名称和一个包含标签和值的对象,然后使用 v-for 呈现单选按钮列表。
我已经成功解决了问题的每一半,但未能将它们结合起来:
- 我可以制作一组绑定到数据模型的单选按钮,其中按钮是在模板中静态定义的,但我不知道如何使列表动态化。这是相关代码:
//component
const Radio = {
template: '#test',
prop: ['value'],
data () {
return {
selected: this.value
}
},
model: {
prop: 'value',
event: 'change'
},
methods: {
handleClickInput (e) {
this.$emit('change', this.selected)
}
}
}
//app
var app2 = new Vue({
el: '#app2',
data: {
door: '',
doorOptions: {
'Yes': 1,
'No': 0,
}
},
components: { Radio, }
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app2">
<radio v-model="door"></radio>
<p>
door = {{door}}
</p>
</div>
<template id="test">
<div>
<input type="radio" value="0" v-model="selected" @change="handleClickInput">0
<input type="radio" value="1" v-model="selected" @change="handleClickInput">1
</div>
</template>
- 我可以根据 "options" 对象制作单选按钮的动态列表,但找不到将它们绑定到数据模型的方法。这是相关代码:
// component
Vue.component('radio-set', {
template: '#radio-set',
props: {
'label-name': '',
'variable': '',
'options': '',
},
methods: {
clicked: function(variable, key, value) {
// none of this is right, it doesn't update the vue data model
window[variable] = value; //assign the new value to the dynamic variable name
selected = value;
this.$emit("click-event", variable) //create the click event for model updating by the parent
}
},
})
//app
var app = new Vue({
el: '#vueApp',
data: {
door:'initial value',
doorOptions: {
'Yes':1,
'No':0,
'Maybe':5,
'A new option':25
},
},
methods: {
buttonClick: function(p1){
console.log(p1+': '+window[p1]); //the variable was assigned inside the child component
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="vueApp">
<radio-set
label-name="Radio button set"
variable="door"
:options="doorOptions"
@click-event="buttonClick"
>door: {{door}}
</radio-set>
</div>
<template id="radio-set">
<div>
<label>{{labelName}}:</label>
<button
type="button"
v-for="(val, key) in options"
@click="clicked(variable, key, val)"
>
{{ key }}
</button>
</div>
</template>
任何人都可以就我如何前进提供一些指导吗?
首先:对于你的选择,有一个数组会更容易。
doorOptions: [
{ key: "Yes", value: 1 },
{ key: "No", value: 0 },
{ key: "Maybe", value: 5 },
{ key: "A new option", value: 25 }
]
};
这样你就可以遍历它了。
在您的自定义组件和您的应用程序之间同步所选值的另一个好方法是使用 v-model。
A tutorial to implement v-model
这样我们就可以创建一个像这样的可重用组件:
<template>
<div>
<label>{{labelName}}:</label>
<button
type="button"
v-for="(val, idx) in options"
:key="idx"
@click="clicked(val)"
>{{ val.key }}</button>
</div>
</template>
<script>
export default {
props: ["value", "options", "labelName"],
methods: {
clicked(val) {
this.$emit("input", val);
}
}
};
</script>
然后像这样使用它
<template>
<div id="app">
<radio-set v-model="selected" label-name="Radio button set" :options="doorOptions"/>
Selected : {{selected.key}}
</div>
</template>
<script>
import RadioSet from "./components/RadioSet";
export default {
name: "App",
components: {
RadioSet
},
data() {
return {
selected: null,
doorOptions: [
{ key: "Yes", value: 1 },
{ key: "No", value: 0 },
{ key: "Maybe", value: 5 },
{ key: "A new option", value: 25 }
]
};
}
};
</script>
如@PierreSaid 所述,您可以阅读更多关于 v-model
在自定义组件上的用法。
这是使用 input[type="radio"]
并将更改事件发回父组件的另一个示例。
// component
Vue.component('radio-set', {
template: '#radio-set',
props: {
'label-name': '',
'value': '',
'options': '',
}
})
//app
var app = new Vue({
el: '#vueApp',
data() {
return {
door: null,
doorOptions: {
'Yes': 1,
'No': 0,
'Maybe': 5,
'A new option': 25
}
};
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.min.js"></script>
<div id="vueApp">
<radio-set label-name="Radio button set" v-model="door" :options="doorOptions"></radio-set>
door: {{door}}
</div>
<template id="radio-set">
<div>
<div>{{labelName}}:</div>
<label v-for="(val, key) in options" :key="val">
<input type="radio"
:name="labelName"
:value="val"
:checked="val == value"
@change="$emit('input', val)">
{{ key }}
</label>
</div>
</template>
在研究和琢磨这些答案的过程中,我想到了以下方法:
- 使用对象数组的首选方法 Vuetify:
new Vue({
el: '#app',
vuetify: new Vuetify(),
data: () => ({
color: {
label: "Choose:",
// Array List
items: [
{ key: 1, value: "Red", color: "red" },
{ key: 2, value: "Green", color: "green" },
{ key: 3, value: "Blue", color: "blue" }
],
selectedItemKey: 2 // Red
}
}),
computed: {
selectedColorItem() {
return this.color.items.find(item => item.key===this.color.selectedItemKey)
}
}
})
<div id="app">
<v-app id="inspire">
<v-container fluid mx-4>
<v-radio-group
:label="color.label"
row
v-model="color.selectedItemKey"
>
<v-radio
:color="item.color"
:key="item.key"
:label="item.value"
:value="item.key"
v-for="(item, index) in color.items"
></v-radio>
</v-radio-group>
Color: <span :class=`${selectedColorItem?.color}--text`>
{{selectedColorItem?.value}}
</span>(key: {{color.selectedItemKey}})
</v-container>
</v-app>
</div>
<link href="https://cdn.jsdelivr.net/npm/@mdi/font@3.x/css/materialdesignicons.min.css" rel="stylesheet"/>
<link href="https://cdn.jsdelivr.net/npm/vuetify@2.0.11/dist/vuetify.min.css" rel="stylesheet"/>
<script src="https://cdn.jsdelivr.net/npm/vue@2.x/dist/vue.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vuetify@2.x/dist/vuetify.js"></script>
根据其他答案之一,我最终得到了 Vue 3。 v-model
的工作方式有一些重大变化,即道具名称。 (https://v3.vuejs.org/guide/migration/v-model.html)
样式是基本的,但我想要一些东西来表明活动选择是什么。
<template>
<div>
<label>{{ labelName }}:</label>
<button
:class="val.key === modelValue ? 'active' : 'inactive'"
type="button"
v-for="(val, idx) in options"
:key="idx"
@click="clicked(val)"
>
{{ val.key }}
</button>
</div>
</template>
<script>
export default {
props: ["modelValue", "options", "labelName"],
methods: {
clicked(val) {
console.log("emitting click", val.key);
this.$emit("update:modelValue", val.key);
},
}
};
</script>
<style scoped>
button {
padding: 10px;
margin: 5px;
}
.active {
background-color: #42b983;
}
.inactive {
background-color: lightgray;
}
</style>
它以同样的方式使用。我只是将一个基本数组映射到 {key, value} 因为这就是我所需要的,但是做一些更明确的事情会很容易。
<template>
<radio-set
label-name="On / Off"
v-model="myValue"
:options="options.radioOptions"
></radio-set>
</template>
<script>
import RadioSet from "./RadioSet.vue";
let options = {
radioOptions: ["on", "off"].map((x) => {
return { key: x, val: x };
}),
};
export default {
name: "MyComponent",
components: {
RadioSet,
},
data: () => {
return {
options,
myValue: "unknown",
};
},
};
</script>