Почему сразу все чек-боксы отмечаются активными Vue.js?

Начал изучать Vue.js и столкнулся вот с такой проблемой. У меня есть компонент MyCheckbox, в котором просто кастомный чек бокс. Собственно ближе к делу, что у меня странно работает. Когда я нажимаю на один чекбокс срабатывают сразу все.

#parent.vue
<script setup>
  import {ref} from "vue";
  import CheckBox from "@/components/CheckBox.vue";

  let count = ref(0);
  let checked = ref(['Jack']);

  function increment() {
    count.value++
  }
</script>

<template>
  <h1>{{ checked }}</h1>
  <CheckBox name="Some_name1" v-model="checked" id="A"/>
  <CheckBox v-model="checked" name="Some_name2" id="v"/>
  <CheckBox v-model="checked" name="Some_name3" id="b"/>
  <CheckBox v-model="checked" name="Some_name4" id="a"/>
</template>

Мне нужно, чтобы через v-model, имя чекбокса добавлялось в список checked (без компонентного чекбокса это работает без всяких проблем).

#CheckBox.vue
<script setup>
defineProps({
  name: String,
  id: String
})

const model = defineModel()


function printName() {
  console.log(model)
}
</script>

<template>
  <input type="checkbox" class="checkbox" id={{id}} value={{name}} v-model="model" @click="printName">
  <label>Hello</label>
</template>

<style scoped>некоторые стили</style>

Во-первых, нажимая на один чекбокс, имя, которое добавляется в список имеет такой вид: "{{name}}". И во-вторых уже выше упомянутая проблема, что все чекбоксы отмечаются одновременно вместе


Ответы (1 шт):

Автор решения: Alex Mar

Во-первых: неправильное использование переменных в шаблоне вашего кода.ы использовали {{name}} в атрибутах, это было буквальным строковым значением, а не переменной.

<input type="checkbox" class="checkbox" :id="id" :value="name" v-model="model" @click="printName">

Во-вторых: обратите внимание как вы используете v-model в вашем компоненте и как передаёте данные между родительским и дочерним компонентами. Когда вы используете v-model с массивом в родителе и одновременно привязываете его ко всем чекбоксам, это интерпретируется так, что все чекбоксы управляют одним и тем же состоянием. Поэтому, изменяя состояние одного чекбокса, вы меняете состояние всех чекбоксов, связанных с этим массивом.

v-model из parent.vue связан с массивом и его обновление происходит через событие update:modelValue, которое обрабатывается в дочернем компоненте: ваш пример на https://play.vuejs.org/

#CheckBox.vue
<script setup>
import { defineProps, defineEmits } from "vue";

const props = defineProps({
  modelValue: Array, // массив для v-model
  name: String,
  id: String
});

const emit = defineEmits(['update:modelValue']);

function toggleCheck(event) {
  const newValue = event.target.checked 
     // Если чекбокс отмечен, добавляем его имя в массив modelValue
     ? [...props.modelValue, props.name] 
     // Если чекбокс снят, удаляем его имя из массива modelValue
     : props.modelValue.filter(item => item !== props.name);
  emit('update:modelValue', newValue); // Обновляем modelValue
}
</script>

<template>
  <input type="checkbox" :id="id" :value="name" :checked="modelValue.includes(name)" @change="toggleCheck">
  <label :for="id">{{name}}</label>
</template>

ПС:

  • Для чекбокса используется событие change вместо click, потому что это более логично для обработки изменений его состояния.

  • В шаблоне используется :checked="modelValue.includes(name)" для
    определения, должен ли чекбокс быть отмеченным, основываясь на
    текущем состоянии modelValue.

→ Ссылка