dev.syw

v-model로 입력·체크박스·셀렉트를 양방향 바인딩하기.

폼 입력 바인딩 (v-model)

폼을 다루다 보면 "입력값을 상태에 반영하고, 상태가 바뀌면 입력창에도 반영"하는 양방향 동기화가 끝없이 필요합니다. Vue는 이걸 v-model 한 줄로 해결합니다. 텍스트 입력부터 체크박스·라디오·셀렉트까지, 그리고 직접 만든 컴포넌트에도 v-model 을 쓸 수 있습니다.

학습 목표

  • v-model 의 양방향 바인딩 원리를 이해한다.
  • 입력·체크박스·라디오·셀렉트별 바인딩 방식을 안다.
  • .lazy·.number·.trim 수식어를 활용한다.
  • 커스텀 컴포넌트에 v-model 을 적용한다.

v-model의 원리

v-model 은 사실 value 바인딩 + 이벤트 리스너를 합친 축약입니다. 텍스트 입력에서는 다음 두 줄과 같습니다.

<!-- 이 둘은 같다 -->
<input v-model="text" />
<input :value="text" @input="text = $event.target.value" />

그래서 상태가 바뀌면 입력창이, 입력하면 상태가 동시에 갱신됩니다.

<script setup>
import { ref } from 'vue';
const text = ref('');
</script>

<template>
  <input v-model="text" placeholder="입력해 보세요" />
  <p>입력값: {{ text }}</p>
</template>

체크박스

단일 체크박스는 boolean에, 여러 체크박스는 배열에 묶습니다.

<script setup>
import { ref } from 'vue';
const agree = ref(false);
const hobbies = ref([]);   // 체크된 값들이 모임
</script>

<template>
  <label><input type="checkbox" v-model="agree" /> 동의</label>

  <label><input type="checkbox" value="독서" v-model="hobbies" /> 독서</label>
  <label><input type="checkbox" value="운동" v-model="hobbies" /> 운동</label>
  <p>{{ hobbies }}</p>
</template>

라디오와 셀렉트

<script setup>
import { ref } from 'vue';
const gender = ref('');
const city = ref('seoul');
</script>

<template>
  <label><input type="radio" value="남" v-model="gender" /></label>
  <label><input type="radio" value="여" v-model="gender" /></label>

  <select v-model="city">
    <option value="seoul">서울</option>
    <option value="busan">부산</option>
  </select>
</template>

라디오는 선택된 value 하나가, 셀렉트는 고른 <option>value 가 상태에 담깁니다.

수식어

v-model 뒤에 수식어를 붙여 입력을 가공할 수 있습니다.

<template>
  <input v-model.lazy="text" />    <!-- input 대신 change 시점에 갱신 -->
  <input v-model.number="age" />   <!-- 숫자로 형변환 -->
  <input v-model.trim="name" />    <!-- 앞뒤 공백 제거 -->
</template>
수식어효과
.lazy입력 중이 아닌 change(포커스 아웃 등) 때 갱신
.number입력을 숫자로 변환
.trim앞뒤 공백 자동 제거

💡 TIP — 숫자 입력(type="number")이라도 기본은 문자열로 들어옵니다. 계산에 쓸 값이면 .number 를 붙이세요.

컴포넌트 v-model

직접 만든 컴포넌트에도 v-model 을 쓸 수 있습니다. Vue 3.4+ 에서는 defineModel 매크로로 간단해졌습니다.

<!-- MyInput.vue -->
<script setup>
const model = defineModel();   // 양방향 바인딩되는 ref
</script>

<template>
  <input v-model="model" />
</template>
<!-- 부모 -->
<template>
  <MyInput v-model="username" />
</template>

defineModel() 이 반환한 model 을 바꾸면 부모의 username 도 함께 갱신됩니다.

⚠️ 주의defineModel 은 Vue 3.4 이상에서 쓸 수 있습니다. 이전 버전이라면 props(modelValue) + emit('update:modelValue', ...) 패턴을 직접 작성해야 합니다.

요약

  • v-model 은 value 바인딩 + 이벤트 리스너를 합친 양방향 동기화다.
  • 체크박스는 boolean/배열, 라디오·셀렉트는 선택된 value에 묶인다.
  • .lazy·.number·.trim 으로 갱신 시점과 형변환을 조절한다.
  • defineModel 로 커스텀 컴포넌트에도 v-model 을 적용한다.

연습문제

  1. 이름 입력창을 v-model.trim 으로 묶고, 입력값과 글자 수를 화면에 표시해 보세요.
  2. 취미를 여러 개 고르는 체크박스 그룹을 만들고 선택 결과 배열을 출력해 보세요.
  3. 나이 입력에 .number 를 붙여, 10을 더한 값을 함께 표시해 보세요. (형변환 효과 확인)
  4. defineModel 을 쓰는 MyInput.vue 를 만들어 부모와 양방향으로 연결해 보세요.

힌트 — 글자 수는 {{ name.length }}. .number 없이 더하면 문자열로 이어붙으니 차이를 비교해 보세요.

💡 연습문제 풀이

불러오는 중…

함께 보면 좋은 자료

댓글 0

Vue.js” 강좌에 대한 댓글입니다.

댓글을 작성하려면 로그인이 필요합니다.