체크박스 그룹을 만들고 선택된 값들을 배열로 관리하는 방법을 알아보자.

기본 사용법

<template>
  <div>
    <div v-for="item in items" :key="item.id">
      <input 
        type="checkbox"
        :value="item.value"
        v-model="selectedItems"
      >
      <label>{{ item.label }}</label>
    </div>
    
    <p>선택된 항목: {{ selectedItems }}</p>
  </div>
</template>
 
<script setup>
import { ref } from 'vue'
 
const items = ref([
  { id: 1, value: 'apple', label: '사과' },
  { id: 2, value: 'banana', label: '바나나' },
  { id: 3, value: 'orange', label: '오렌지' }
])
 
const selectedItems = ref([]) // 선택된 값들이 이 배열에 저장됨
</script>

고급 활용

1. 전체 선택 기능

<template>
  <div>
    <!-- 전체 선택 체크박스 -->
    <div>
      <input 
        type="checkbox"
        :checked="isAllSelected"
        @change="toggleAll"
      >
      <label>전체 선택</label>
    </div>
 
    <!-- 개별 체크박스 -->
    <div v-for="item in items" :key="item.id">
      <input 
        type="checkbox"
        :value="item.value"
        v-model="selectedItems"
      >
      <label>{{ item.label }}</label>
    </div>
  </div>
</template>
 
<script setup>
import { ref, computed } from 'vue'
 
const items = ref([
  { id: 1, value: 'apple', label: '사과' },
  { id: 2, value: 'banana', label: '바나나' },
  { id: 3, value: 'orange', label: '오렌지' }
])
 
const selectedItems = ref([])
 
const isAllSelected = computed(() => 
  items.value.length === selectedItems.value.length
)
 
const toggleAll = () => {
  selectedItems.value = isAllSelected.value 
    ? [] 
    : items.value.map(item => item.value)
}
</script>

2. 비활성화 상태 관리

<template>
  <div v-for="item in items" :key="item.id">
    <input 
      type="checkbox"
      :value="item.value"
      v-model="selectedItems"
      :disabled="isItemDisabled(item)"
    >
    <label :class="{ 'text-gray-400': isItemDisabled(item) }">
      {{ item.label }}
    </label>
  </div>
</template>
 
<script setup>
import { ref } from 'vue'
 
const items = ref([
  { id: 1, value: 'apple', label: '사과', status: 'active' },
  { id: 2, value: 'banana', label: '바나나', status: 'inactive' },
  { id: 3, value: 'orange', label: '오렌지', status: 'active' }
])
 
const selectedItems = ref([])
 
const isItemDisabled = (item) => item.status === 'inactive'
</script>

3. 선택 항목 감시 및 처리

<script setup>
import { ref, watch } from 'vue'
import { updateSelections } from '@/api/selections'
 
const selectedItems = ref([])
 
watch(selectedItems, async (newVal) => {
  try {
    await updateSelections(newVal)
  } catch (error) {
    console.error('선택 항목 업데이트 실패:', error)
  }
})
</script>

실제 활용 예제: 권한 관리

<template>
  <div class="space-y-4">
    <div 
      v-for="group in permissionGroups" 
      :key="group.id"
      class="border rounded p-4"
    >
      <div class="flex items-center space-x-2 mb-3">
        <input
          type="checkbox"
          :checked="isGroupSelected(group)"
          @change="toggleGroup(group)"
          class="form-checkbox"
        >
        <h3 class="font-bold">{{ group.name }}</h3>
      </div>
 
      <div class="ml-6 space-y-2">
        <div 
          v-for="permission in group.permissions"
          :key="permission.id"
          class="flex items-center space-x-2"
        >
          <input
            type="checkbox"
            :value="permission.id"
            v-model="selectedPermissions"
            :disabled="permission.locked"
            class="form-checkbox"
          >
          <div>
            <label class="text-sm">{{ permission.name }}</label>
            <p class="text-xs text-gray-500">{{ permission.description }}</p>
          </div>
        </div>
      </div>
    </div>
  </div>
</template>
 
<script setup>
import { ref, computed } from 'vue'
 
const permissionGroups = ref([
  {
    id: 'users',
    name: '사용자 관리',
    permissions: [
      {
        id: 'users:read',
        name: '사용자 조회',
        description: '사용자 목록 및 상세 정보 조회',
        locked: false
      },
      {
        id: 'users:write',
        name: '사용자 수정',
        description: '사용자 정보 생성 및 수정',
        locked: false
      },
      {
        id: 'users:delete',
        name: '사용자 삭제',
        description: '사용자 계정 삭제',
        locked: true
      }
    ]
  }
])
 
const selectedPermissions = ref([])
 
const isGroupSelected = (group) => {
  const availablePermissions = group.permissions
    .filter(p => !p.locked)
    .map(p => p.id)
  
  return availablePermissions.every(p => 
    selectedPermissions.value.includes(p)
  )
}
 
const toggleGroup = (group) => {
  const availablePermissions = group.permissions
    .filter(p => !p.locked)
    .map(p => p.id)
  
  if (isGroupSelected(group)) {
    selectedPermissions.value = selectedPermissions.value
      .filter(p => !availablePermissions.includes(p))
  } else {
    selectedPermissions.value = [
      ...selectedPermissions.value,
      ...availablePermissions
    ]
  }
}
</script>

컴포넌트 추출과 재사용

// CheckboxGroup.vue
<template>
  <div class="checkbox-group">
    <div class="group-header">
      <input
        type="checkbox"
        :checked="isAllSelected"
        @change="toggleAll"
      >
      <label>{{ title }}</label>
    </div>
    
    <div class="group-items">
      <slot></slot>
    </div>
  </div>
</template>
 
<script setup>
import { computed } from 'vue'
 
const props = defineProps({
  modelValue: {
    type: Array,
    required: true
  },
  options: {
    type: Array,
    required: true
  },
  title: {
    type: String,
    default: '전체 선택'
  }
})
 
const emit = defineEmits(['update:modelValue'])
 
const isAllSelected = computed(() => 
  props.options.length === props.modelValue.length
)
 
const toggleAll = () => {
  emit('update:modelValue', 
    isAllSelected.value 
      ? [] 
      : props.options.map(option => option.value)
  )
}
</script>
// 사용 예시
<template>
  <CheckboxGroup
    v-model="selectedFruits"
    :options="fruits"
    title="과일 선택"
  >
    <div v-for="fruit in fruits" :key="fruit.id">
      <input
        type="checkbox"
        :value="fruit.value"
        v-model="selectedFruits"
      >
      <label>{{ fruit.label }}</label>
    </div>
  </CheckboxGroup>
</template>
 
<script setup>
import { ref } from 'vue'
import CheckboxGroup from './CheckboxGroup.vue'
 
const fruits = ref([
  { id: 1, value: 'apple', label: '사과' },
  { id: 2, value: 'banana', label: '바나나' },
  { id: 3, value: 'orange', label: '오렌지' }
])
 
const selectedFruits = ref([])
</script>