具有 v-model 和项目数组的 Vue 3 自定义复选框组件

Posted

技术标签:

【中文标题】具有 v-model 和项目数组的 Vue 3 自定义复选框组件【英文标题】:Vue 3 custom checkbox component with v-model and array of items 【发布时间】:2021-11-27 10:41:30 【问题描述】:

迫切需要你们的帮助。

所以基本上我有一个 带有 v-model 的自定义复选框组件。我在组件上使用 v-for 循环来显示带有数组名称的复选框。在父组件中,我有两列可用和选定。这个想法是,如果我选中 Available 列 中的一个框,它应该会出现在 Selected column 上。问题是它按字母显示而不是全名。

我能够在没有复选框组件的情况下实现所需的结果,但由于在我的项目中我将需要很多复选框,因此我希望有一个组件。

请点击以下链接获取代码: CodeSandBox

不要介意样式的差异。

问题:

期望的结果:

【问题讨论】:

【参考方案1】:

有两个问题。第一个问题是,您将v-model 设置为v-model="filter.filterCollection",因此您选择的复选框将作为字符串存储到数组中,如果您选择另一个复选框,则字符串将被覆盖。第二个问题是,您将该存储的字符串称为数组。这导致您的字符串(一个字母数组)将为每个字母呈现。所以“数字”就像["N", "u", "m", "b", "e", "r"]

要解决您的问题,您需要将每个选择及其自己的引用存储在您的v-model 中。为了满足您正确列出和正确删除的需求,您需要应用以下更改:

你的复选框循环

<Checkbox
   v-for="(item, index) in items"
   :key="item.id"
   :label="item.name"
   :id="index"
   :isChecked="isChecked(index)" // this is new
   @remove-selected-filter="removeSelectedFilter" // This is new
   :modelValue="item.name"
   v-model="filter.filterCollection[index]" // Change this
/>

你的 v-model

filter: 
        filterCollection:  // Object instead of array
      

FilterPopUp.vue 中的方法

methods: 
    removeSelectedFilter(index) 
      delete this.filter.filterCollection[index];
    ,
    isChecked(index) 
      return !!this.filter.filterCollection[index];
    
  

你的 Checkbox.vue:

<template>
  <label>
    <p> label </p>
    <input
      type="checkbox"
      :id="id"
      :value="modelValue"
      :checked="isChecked"
      @change="emitUncheck($event.target.checked)"
      @input="$emit('update:modelValue', $event.target.value)"
    />
    <span class="checkmark"></span>
  </label>
</template>

<script>
export default 
  name: "Checkbox",
  props: 
    modelValue:  type: String, default: "" ,
    isChecked: Boolean,
    label:  type: String ,
    value:  type: Array ,
    id:  type: Number ,
  ,
  methods: 
    emitUncheck(event) 
      if(!event)
        this.$emit('remove-selected-filter', this.id);
      
    
  
;
</script>

现在应该可以正确显示您的项目,正确删除项目并在删除项目后取消选中复选框。

【讨论】:

那么删除项目呢? :-) 非常感谢您的帮助,但现在我遇到了另一个问题,如果我单击所选列上的删除项目 SVG,它会删除该项目,但该框仍然在可用列中保持选中状态。有什么想法吗? @Fersek 由于 Tolbxela 的回答也导致该复选框仍处于选中状态,因此我编辑了我的回答,这应该可以满足您的需要。 @Fersek 在我的回答中对Checkbox.vuecheckbox loop 进行了更改。它现在应该可以删除和取消选中。告诉我。 @StevenSiebert 现在就像一个魅力。非常感谢!【参考方案2】:

StevenSiebert 已正确指出您的错误。

但他的解决方案并不完整,因为当您取消选中其中一个过滤器时,不会从集合中删除过滤器。

这是我对您的复选框按预期工作的完整解决方案:

Checkbox.vue

<template>
  <label>
    <p> label </p>
    <input
      type="checkbox"
      :id="id"
      v-model="checked"
      @change="$emit('change',  id: this.id, checked: this.checked)"
    />
    <span class="checkmark"></span>
  </label>
</template>

<script>
export default 
  name: "Checkbox",
  props: 
    modelValue:  type: Boolean, default: false ,
    label:  type: String ,
    id:  type: Number ,
  ,
  emits: ["change"],
  data() 
    return 
      checked: this.modelValue
    ;
  
;
</script>

FilterPopUp.vue

<template>
   ...
       <Checkbox
          v-for="(item, index) in items"
          :key="index"
          :label="item.name"
          :id="index"
          @change="onChange"
        />
  ...            

</template>

<script>
...
methods: 
    removeSelectedFilter(index) 
      this.filter.filterCollection.splice(index, 1);
    ,
    onChange(args) 
      const id, checked = args;
      const item = this.items[id].name;
      if (checked) 
        if (this.filter.filterCollection.indexOf(item) < 0) 
         this.filter.filterCollection.push(item);
        
       else 
        this.filter.filterCollection = this.filter.filterCollection.filter( i=> i != item);
      
    ,
  ,
...

这是工作的 CodeSandbox:

https://codesandbox.io/s/pensive-shadow-ygvzb?file=/src/components/Checkbox.vue

当然,有很多方法可以做到这一点。如果有人有更好更短的方法,请发布您的解决方案。看看会很有趣。

【讨论】:

这会导致在您从列表中删除项目后复选框仍然处于选中状态。 是的,你是对的。我不想自己做所有的工作。 :-)

以上是关于具有 v-model 和项目数组的 Vue 3 自定义复选框组件的主要内容,如果未能解决你的问题,请参考以下文章

Vue.js 如何在 v-model 输入的数组中定位具有未知名称的对象

具有对象数组的多选和 v-model

v-model 在 Vue 2.x 中都有哪些限制?

vue 自定义组件使用v-model

Vue 2 contentEditable 与 v-model

11、Vue3 v-model自定义修饰符