在 Vue 3 中创建复选框组件时实现组的正确方法是什么?
What is the proper way to implement groups when creating a checkbox component in Vue 3?
我正在 Vue 3 中创建一个复选框组件,它使用 v-model
为复选框组创建到数组的绑定。此组绑定是一项可选功能,在大多数情况下,复选框的值不会填充数组,而是 null
或某个字符串。我想我离解决方案越来越近了,但它似乎相当复杂,尤其是考虑到您可以像这样非常简单地绑定 3 个输入:https://medium.com/dataseries/vue-3-v-model-c896566aed64
这是我在 App.vue
中的实现
<template>
<checkbox modelValue="apple" v-model:group="group" />
<checkbox modelValue="orange" v-model:group="group" />
<checkbox modelValue="grape" v-model:group="group" />
<p>{{ group }}</p>
</template>
<script setup>
import { ref } from 'vue';
import Checkbox from './components/Checkbox.vue'
const group = ref(["apple"]); //"Apple" should start out checked, but it currently doesn't.
</script>
这里是Checkbox.vue
<template>
<input
type="checkbox"
:value="modelValue"
@change="updateValue($event)"
/>
<label for="checkbox">{{ modelValue }}</label>
</template>
<script setup>
import { defineEmits, ref, onMounted } from 'vue';
const checkbox = ref(null);
const props = defineProps({
modelValue: String,
group: Array
})
const emit = defineEmits(['update:modelValue'])
onMounted(()=>{
//Some code to determine initial state depending on what props.group looks like?
})
function updateValue(e) {
if (e.target.checked){
props.group.push(e.target.value);
}
if(!e.target.checked){
const toRemove = props.group.indexOf(e.target.value);
props.group.splice(toRemove, 1);
}
emit('update:modelValue', props.group)
}
defineExpose({ checkbox})
</script>
目前,数组根据选中和未选中的内容填充和取消填充,但最初设置为选中的“apple”目前不是。令我困扰的是,输入的实现可以如此简单,但我发现自己编写了一大堆代码来保持复选框组和 group
数组之间的双向绑定。在我深入 onMounted
钩子中编写一大堆代码之前,我想知道是否有更简单的方法来完成所有这些工作?甚至我为 updateValue()
编写的代码似乎有点太多了。
并不是说实现 pr 路径是错误的,但我倾向于使用 v-model
和 watch
而不是事件侦听器。我相信这使得处理重复值之类的事情变得更简单。
App.vue
<template>
<checkbox value="apple" v-model="group" />
<checkbox value="orange" v-model="group" />
<checkbox value="grape" v-model="group" />
<hr/><!-- duplicates -->
<checkbox value="apple" v-model="group" />
<checkbox value="grape" v-model="group" />
<p>{{ group }}</p>
</template>
<script setup>
import { ref } from 'vue';
import Checkbox from './Checkbox.vue'
const group = ref(["apple"]);
</script>
Checkbox.vue
<template>
<label>
<input
type="checkbox"
:value="value"
v-model="checked"
/>
{{ value }}
</label>
</template>
<script setup>
import { watch, ref } from 'vue';
const checkbox = ref(null);
const props = defineProps({
modelValue: Array,
value: String
});
const checked = ref(props.modelValue.includes(props.value));
watch(checked, (v) => {
if(!v && props.modelValue.includes(props.value)) {
const toRemove = props.modelValue.indexOf(props.value);
props.modelValue.splice(toRemove, 1);
} else if(v && !props.modelValue.includes(props.value)) {
props.modelValue.push(props.value);
}
})
watch(props.modelValue, (mv) => {
if(checked.value && !mv.includes(props.value)) {
checked.value = false;
} else if(!checked.value && mv.includes(props.value)) {
checked.value = true;
}
})
</script>
在示例中,我使用了 ref
来存储内部 true/false 值。然后有两个手表处理 checked
和 modelValue
之间的差异(映射到组数组)。
我正在 Vue 3 中创建一个复选框组件,它使用 v-model
为复选框组创建到数组的绑定。此组绑定是一项可选功能,在大多数情况下,复选框的值不会填充数组,而是 null
或某个字符串。我想我离解决方案越来越近了,但它似乎相当复杂,尤其是考虑到您可以像这样非常简单地绑定 3 个输入:https://medium.com/dataseries/vue-3-v-model-c896566aed64
这是我在 App.vue
<template>
<checkbox modelValue="apple" v-model:group="group" />
<checkbox modelValue="orange" v-model:group="group" />
<checkbox modelValue="grape" v-model:group="group" />
<p>{{ group }}</p>
</template>
<script setup>
import { ref } from 'vue';
import Checkbox from './components/Checkbox.vue'
const group = ref(["apple"]); //"Apple" should start out checked, but it currently doesn't.
</script>
这里是Checkbox.vue
<template>
<input
type="checkbox"
:value="modelValue"
@change="updateValue($event)"
/>
<label for="checkbox">{{ modelValue }}</label>
</template>
<script setup>
import { defineEmits, ref, onMounted } from 'vue';
const checkbox = ref(null);
const props = defineProps({
modelValue: String,
group: Array
})
const emit = defineEmits(['update:modelValue'])
onMounted(()=>{
//Some code to determine initial state depending on what props.group looks like?
})
function updateValue(e) {
if (e.target.checked){
props.group.push(e.target.value);
}
if(!e.target.checked){
const toRemove = props.group.indexOf(e.target.value);
props.group.splice(toRemove, 1);
}
emit('update:modelValue', props.group)
}
defineExpose({ checkbox})
</script>
目前,数组根据选中和未选中的内容填充和取消填充,但最初设置为选中的“apple”目前不是。令我困扰的是,输入的实现可以如此简单,但我发现自己编写了一大堆代码来保持复选框组和 group
数组之间的双向绑定。在我深入 onMounted
钩子中编写一大堆代码之前,我想知道是否有更简单的方法来完成所有这些工作?甚至我为 updateValue()
编写的代码似乎有点太多了。
并不是说实现 pr 路径是错误的,但我倾向于使用 v-model
和 watch
而不是事件侦听器。我相信这使得处理重复值之类的事情变得更简单。
App.vue
<template>
<checkbox value="apple" v-model="group" />
<checkbox value="orange" v-model="group" />
<checkbox value="grape" v-model="group" />
<hr/><!-- duplicates -->
<checkbox value="apple" v-model="group" />
<checkbox value="grape" v-model="group" />
<p>{{ group }}</p>
</template>
<script setup>
import { ref } from 'vue';
import Checkbox from './Checkbox.vue'
const group = ref(["apple"]);
</script>
Checkbox.vue
<template>
<label>
<input
type="checkbox"
:value="value"
v-model="checked"
/>
{{ value }}
</label>
</template>
<script setup>
import { watch, ref } from 'vue';
const checkbox = ref(null);
const props = defineProps({
modelValue: Array,
value: String
});
const checked = ref(props.modelValue.includes(props.value));
watch(checked, (v) => {
if(!v && props.modelValue.includes(props.value)) {
const toRemove = props.modelValue.indexOf(props.value);
props.modelValue.splice(toRemove, 1);
} else if(v && !props.modelValue.includes(props.value)) {
props.modelValue.push(props.value);
}
})
watch(props.modelValue, (mv) => {
if(checked.value && !mv.includes(props.value)) {
checked.value = false;
} else if(!checked.value && mv.includes(props.value)) {
checked.value = true;
}
})
</script>
在示例中,我使用了 ref
来存储内部 true/false 值。然后有两个手表处理 checked
和 modelValue
之间的差异(映射到组数组)。