带有 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 你的解决方案。看看会很有趣
迫切需要你们的帮助。
基本上我有一个 自定义复选框组件和一个 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 你的解决方案。看看会很有趣