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

Vue 3 custom checkbox component with v-model and array of items

迫切需要你们的帮助。

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

我可以在没有复选框组件的情况下实现预期的结果,但由于我在我的项目中经常需要复选框,所以我想为其配备一个组件。

代码请参考link: CodeSandBox

不介意样式上的差异。

问题:

期望的结果:

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

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

你的复选框循环

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

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

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

当然,有很多方法可以做到。如果有人有更好更短的方法,请 post 你的解决方案。看看会很有趣