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을 적용한다.
연습문제
- 이름 입력창을
v-model.trim으로 묶고, 입력값과 글자 수를 화면에 표시해 보세요. - 취미를 여러 개 고르는 체크박스 그룹을 만들고 선택 결과 배열을 출력해 보세요.
- 나이 입력에
.number를 붙여, 10을 더한 값을 함께 표시해 보세요. (형변환 효과 확인) defineModel을 쓰는MyInput.vue를 만들어 부모와 양방향으로 연결해 보세요.
힌트 — 글자 수는
{{ name.length }}..number없이 더하면 문자열로 이어붙으니 차이를 비교해 보세요.
💡 연습문제 풀이
불러오는 중…
댓글 0
“Vue.js” 강좌에 대한 댓글입니다.