Vue:在自定义复选框组件中与v-model绑定不起作用

时间:2019-10-01 14:44:08

标签: vue.js checkbox v-model

我正在尝试构建一个自定义复选框组件,该组件具有通过带有选项和值的数组通过v-for循环生成的选项。如何将v模型正确绑定到复选框组件,以便正确更新它?

现在的问题是,该模型仅更新到已选中的最新复选框,而没有给出具有所有选中选项的数组。

Vue.component('ui-checkbox', {
	 props: {   
    label: {
      type: String,
      required: true,
    },
    index: {
      type: Number
    },
    inputValue: {
      type: String
    }
  },
  methods: {
    onChange(e) {
      this.$emit('input', e.target.value);
    },
  },
	template: `<div>
    <input 
      :id="index"
      type="checkbox"
      :value="inputValue"
      @change="onChange" />
    <label :for="index">
      {{ label }}
    </label>
  </div>`,
})

new Vue({
  el: "#app",
  data: {
    checkOptions: [
      {
        label: 'Option 1',
        value: 'value of option 1',
      },
      {
        label: 'Option 2',
        value: 'value of option 2',
      },
      {
        label: 'Option 3',
        value: 'value of option 3',
      },
      {
        label: 'Option 4',
        value: 'value of option 4',
      },
    ],
    myCheckBoxModel: []
  },
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
   <span>checked Checkboxes: {{ myCheckBoxModel }} </span>
   <ui-checkbox
     v-for="(option, index) in checkOptions"
     v-model="myCheckBoxModel"
     :key="index"
     :index="index"
     :input-value="option.value"
     :label="option.label" />    
</div>

2 个答案:

答案 0 :(得分:0)

完成时

this.$emit('input', e.target.value);

它的作用类似于

myCheckBoxModel = e.target.value

因此,它只是将您单击的最后一个复选框的值分配给myCheckBoxModel。 如果要将所有选中的项目保留在myCheckBoxModel中,则需要执行以下操作:

  1. value组件添加ui-checkbox属性,以访问myCheckBoxModel的当前值。 Value是该目标的默认属性名称(请参见vue guide)。
  2. 在您的onChange方法中,将当前值复制到该变量,因为直接突变value属性并不好
  3. 如果您的复选框已选中,则将对应的值推送到数组。如果未选中该复选框,请从数组中删除对应的值
  4. 发出input事件,并将结果数组作为值

Vue.component('ui-checkbox', {
    	 props: {   
        label: {
          type: String,
          required: true,
        },
        index: {
          type: Number
        },
        inputValue: {
          type: String
        },
        value: {
          type: Array
        }
      },
      methods: {
        onChange(e) {
          let currentValue = [...this.value]
          if (e.target.checked) {
            currentValue.push(e.target.value) 
          } else {
            currentValue = currentValue.filter(item => item !== e.target.value)
          }
          this.$emit('input', currentValue);
        },
      },
    	template: `<div>
        <input 
          :id="index"
          type="checkbox"
          :value="inputValue"
          @change="onChange" />
        <label :for="index">
          {{ label }}
        </label>
      </div>`,
    })

    new Vue({
      el: "#app",
      data: {
        checkOptions: [
          {
            label: 'Option 1',
            value: 'value of option 1',
          },
          {
            label: 'Option 2',
            value: 'value of option 2',
          },
          {
            label: 'Option 3',
            value: 'value of option 3',
          },
          {
            label: 'Option 4',
            value: 'value of option 4',
          },
        ],
       myCheckBoxModel: []
      }
    })
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
  <div id="app">
  checked Checkboxes:
       <span v-for="item in myCheckBoxModel"> {{ item }}; </span>
       <ui-checkbox
         v-for="(option, index) in checkOptions"
         v-model="myCheckBoxModel"
         :key="index"
         :index="index"
         :input-value="option.value"
         :label="option.label" />    
  </div>

我不知道您是否需要以编程方式设置复选框状态,即,当您更改myCheckBoxModel时,复选框的状态会相应地更改。如果这样做,则需要监视value组件中的ui-checkbox属性:取决于复选框的值是否位于value数组中,设置复选框的状态。如果要通过created初始化复选框的状态,请在myChexkboxModel钩子中执行相同的操作

答案 1 :(得分:0)

@Lana 提出的解决方案太复杂了。根本不需要 onChange 方法 - 您想要的是使用 v-model 的内置功能。见下文...

Vue.component('ui-checkbox', {
  props: {
    label: {
      type: String,
      required: true,
    },
    index: {
      type: Number
    },
    inputValue: {
      type: String
    },
    value: {
      type: Array
    }
  },
  computed: {
    model: {
      get() {
        return this.value
      },
      set(value) {
        this.$emit('input', value)
      }
    },
  },
  template: `<div>
        <input 
          :id="index"
          type="checkbox"
          :value="inputValue"
          v-model="model" />
        <label :for="index">
          {{ label }}
        </label>
      </div>`,
})

new Vue({
  el: "#app",
  data: {
    checkOptions: [{
        label: 'Option 1',
        value: 'value of option 1',
      },
      {
        label: 'Option 2',
        value: 'value of option 2',
      },
      {
        label: 'Option 3',
        value: 'value of option 3',
      },
      {
        label: 'Option 4',
        value: 'value of option 4',
      },
    ],
    myCheckBoxModel: []
  }
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
  model: {{ myCheckBoxModel }}
  <ui-checkbox v-for="(option, index) in checkOptions" v-model="myCheckBoxModel" :key="index" :index="index" :input-value="option.value" :label="option.label" />
</div>