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

迫切需要你们的帮助。

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

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

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

不要介意样式的差异。

问题:

期望的结果:

【问题讨论】:

    标签: javascript vue.js vue-component vuejs3 v-model


    【解决方案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

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

    【讨论】:

    • 这会导致在您从列表中删除项目后复选框仍然处于选中状态。
    • 是的,你是对的。我不想自己做所有的工作。 :-)
    猜你喜欢
    • 2020-09-24
    • 2017-11-07
    • 2021-08-14
    • 2022-01-27
    • 2020-01-30
    • 2020-03-26
    • 2019-02-14
    • 1970-01-01
    • 2018-10-03
    相关资源
    最近更新 更多