具有单选按钮动态列表的 Vue.js v-model

Posted

技术标签:

【中文标题】具有单选按钮动态列表的 Vue.js v-model【英文标题】:Vue.js v-model with dynamic list of radio buttons 【发布时间】:2020-02-23 17:33:11 【问题描述】:

我正在尝试制作一个可重用的 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>
    我可以根据“选项”对象制作单选按钮的动态列表,但找不到将它们绑定到数据模型的方法。下面是代码:

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

任何人都可以提供一些关于我如何前进的建议吗?

【问题讨论】:

【参考方案1】:

正如@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【参考方案2】:

首先:对于您的选择,拥有一个数组会更容易。

      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>

Live demo

【讨论】:

【参考方案3】:

当我研究和玩弄这些答案时,我想出了以下方法:

    使用对象数组和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>

    数组列表 & &lt;label&gt;) - codepen

    对象列表 & &lt;Label&gt;) - codepen

    我看了一下使用@Pierre Said 回答中的按钮,但似乎我需要使用一堆 CSS 来使按钮看起来像单选按钮。

【讨论】:

Vuetify 和 BootstrapVue 都提供灵活的无线电组组件。如果您的项目已经使用其中一个库,那么使用它们是有意义的。但是这个问题是关于从头开始创建一个可重用的无线电组组件。仅为其单选按钮加载一个 Vuetify 大小的库没有多大意义。除此之外,查看您列出的其他两个选项,它们似乎是对已接受答案的抄袭。当您“调整”并重新发布现有解决方案时,您应该正确地对其进行归因并准确阐明您对修改版本的贡献(如果有的话)。【参考方案4】:

基于其他答案之一,我最终得到了 Vue 3v-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.js v-model的主要内容,如果未能解决你的问题,请参考以下文章

根据Android Studio中的字符串值动态添加单选按钮列表?

我无法将我的 v-model 数据传递到我的后端以获取 vue.js 中的单选按钮类型,如何将选中的单选按钮值传递给我的后端?

单选按钮验证(动态名称)

在 vue js 中使用单选按钮时 v-model 没有更新?

Vue js在列表中添加动态字段,删除和排序不起作用

Vue.js小Demo--单选和复选功能实现