Learning
레슨 4 / 9·20분

폼 처리와 v-model

v-model 양방향 바인딩

v-model은 폼 입력과 데이터를 양방향으로 연결하는 디렉티브입니다. 입력값이 변경되면 데이터가 자동 업데이트되고, 데이터가 변경되면 입력 필드도 함께 갱신됩니다.

vue
<script setup lang="ts">
import { ref } from 'vue';

const name = ref('');
const email = ref('');
const age = ref(20);
const agree = ref(false);
const gender = ref('');
const hobbies = ref<string[]>([]);
const bio = ref('');
</script>

<template>
  <form @submit.prevent="handleSubmit">
    <!-- 텍스트 입력 -->
    <input v-model="name" placeholder="이름" />
    <input v-model="email" type="email" placeholder="이메일" />

    <!-- 숫자 (자동 변환) -->
    <input v-model.number="age" type="number" />

    <!-- 체크박스: 단일 (boolean) -->
    <label>
      <input v-model="agree" type="checkbox" /> 약관 동의
    </label>

    <!-- 체크박스: 다중 (배열) -->
    <label><input v-model="hobbies" type="checkbox" value="독서" /> 독서</label>
    <label><input v-model="hobbies" type="checkbox" value="코딩" /> 코딩</label>
    <label><input v-model="hobbies" type="checkbox" value="운동" /> 운동</label>

    <!-- 라디오 버튼 -->
    <label><input v-model="gender" type="radio" value="male" /> 남성</label>
    <label><input v-model="gender" type="radio" value="female" /> 여성</label>

    <!-- textarea -->
    <textarea v-model="bio" placeholder="자기소개"></textarea>

    <button type="submit" :disabled="!agree">가입</button>
  </form>
</template>

v-model 수식어

  • v-model.lazy — input 대신 change 이벤트 시 동기화 (포커스를 벗어날 때)
  • v-model.number — 입력값을 자동으로 숫자로 변환
  • v-model.trim — 앞뒤 공백 자동 제거

컴포넌트에서 v-model

커스텀 컴포넌트에서도 v-model을 지원할 수 있습니다. defineModel() (Vue 3.4+)을 사용하면 간단하게 구현됩니다.

vue
<!-- RatingInput.vue -->
<script setup lang="ts">
// defineModel: v-model 바인딩을 간단하게 구현
const rating = defineModel<number>({ default: 0 });
</script>

<template>
  <div class="rating">
    <button
      v-for="n in 5"
      :key="n"
      @click="rating = n"
      :class="{ active: n <= rating }"
    >
      {{ n <= rating ? '★' : '☆' }}
    </button>
    <span>{{ rating }}점</span>
  </div>
</template>

<!-- 부모에서 사용 -->
<script setup lang="ts">
import RatingInput from './RatingInput.vue';
import { ref } from 'vue';

const score = ref(3);
</script>

<template>
  <RatingInput v-model="score" />
  <p>선택한 점수: {{ score }}</p>
</template>
💡

Vue 3.4 이전에는 커스텀 v-model을 구현하려면 modelValue prop과 update:modelValue emit을 수동으로 정의해야 했습니다. defineModel()은 이 보일러플레이트를 제거해줍니다.