value
를 바인딩하고 @input
이벤트로 text
를 변경하는 것은 번거로울 수 있다. 그래서 Vue에서는 이러한 작업을 단순화 하도록 양방향 바인딩할 수 있는 v-model
디렉티브를 제공한다.<template>
<div>
<h2>input Value</h2>
<input type="text" :value="inputValue" />
<div>{{ inputValue }}</div>
</div>
</template>
import { ref } from "vue";
export default {
setup() {
const inputValue = ref(null);
return { inputValue };
},
};
현재 inputValue
의 값이 null인 상태이다. 값을 넣어보자
이렇게 자바스크립트 상태가 변경되면 input의 value의 상태 또한 변경된다. 왜내면 v-bind
로 binding이 되어 있기 때문이다. 하지만 input 상태가 변경되면 자바스크립트 상태는 그대로다. 이유는 동기화가 되어 있지 않기 때문이다.
<template>
<div>
<h2>input Value</h2>
<input
type="text"
:value="inputValue"
@input="event => (inputValue = event.target.value)"
/>
<div>{{ inputValue }}</div>
</div>
</template>
이렇게 만들면 동기화가 가능하며 이러한 것을 구현한게 v-model
이다.
<template>
<div>
<h2>input Value</h2>
<!-- input -->
<input type="text" v-model="inputValue" />
<div>{{ inputValue }}</div>
<!-- textarea -->
<textarea v-model="textareaValue"></textarea>
<div>{{ textareaValue }}</div>
</div>
</template>
v-model
은 내부적으로 HTML요소가 어떤 요소냐에 따라 서로 다른 속성(:value
)과 이벤트(@input
)를 사용한다.
input, textarea
-> value와 input 이벤트를 사용
checkbox, radio
-> checked와 change 이벤트를 사용
select
-> value와 change 이벤트를 사용
<!-- 단방향 -->
<template>
<div>
<h2>checkbox value</h2>
<label for="checkbox"> {{ checkboxValue }}</label>
<input type="checkbox" id="checkbox" :checked="checkboxValue" />
</div>
</template>
<!-- 양방향 바인딩 -->
<template>
<div>
<h2>checkbox value</h2>
<label for="checkbox"> {{ checkboxValue }}</label>
<input
type="checkbox"
id="checkbox"
:checked="checkboxValue"
@change="event => (checkboxValue = event.target.checked)"
/>
</div>
</template>
<!-- v-model 양방향 바인딩 -->
<template>
<div>
<h2>checkbox value</h2>
<label for="checkbox"> {{ checkboxValue }}</label>
<input type="checkbox" id="checkbox" v-model="checkboxValue"/>
</div>
</template>
import { ref } from "vue";
export default {
setup() {
const checkboxValue = ref(true);
return { checkboxValue };
},
};
현재 checkbox는
true
또는false
로 구분되어 있는데 이것을Yes
또는No
로 구분하고 싶다면true-value="Yes"
,false-value="No"
로 설정하면된다.
<template>
<div>
<h2>checkbox value</h2>
<label for="checkbox"> {{ checkboxValue }}</label>
<input type="checkbox" id="checkbox" v-model="checkboxValue" true-value="Yes" false-value="No"/>
</div>
</template>
import { ref } from "vue";
export default {
setup() {
const checkboxValue = ref("Yes");
return { checkboxValue };
},
};
그리고 checkbox는 한개의 값이 아닌 여러개의 값이 될 수 있다. 배열을 이용하여 만들 수 있다.
<template>
<h2>checkbox value</h2>
<label>
<input type="checkbox" value="html" v-model="checkboxValues" />
html
</label>
<label>
<input type="checkbox" value="css" v-model="checkboxValues" />
css
</label>
<label>
<input type="checkbox" value="javascript" v-model="checkboxValues"/>
javascript
</label>
<div>{{ checkboxValues }}</div>
</template>
import { ref } from "vue";
export default {
setup() {
const checkboxValues = ref([]);
return {
checkboxValues,
};
},
};
이렇게 배열로 양방향을 만들 수 있다.
<!-- 단방향 -->
<template>
<div>
<h2>radio value</h2>
<label>
<input type="radio" name="type" value="A" :checked="radioValue === 'A'"/> A형
</label>
<label>
<input type="radio" name="type" value="AB" :checked="radioValue === 'AB'"/>
AB형
</label>
<div>{{ radioValue }}</div>
</div>
</template>
<!-- 양방향 바인딩 -->
<template>
<div>
<h2>radio value</h2>
<label>
<input
type="radio"
name="type"
value="A"
:checked="radioValue === 'A'"
@change="event => (radioValue = event.target.value)"/>
A형
</label>
<label>
<input
type="radio"
name="type"
value="AB"
:checked="radioValue === 'AB'"
@change="event => (radioValue = event.target.value)"/>
AB형
</label>
<div>{{ radioValue }}</div>
</div>
</template>
<!-- v-model 양방향 바인딩 -->
<template>
<div>
<h2>radio value</h2>
<label>
<input type="radio" name="type" value="A" v-model="radioValue"/>
A형
</label>
<label>
<input type="radio" name="type" value="AB" v-model="radioValue"/>
AB형
</label>
<div>{{ radioValue }}</div>
</div>
</template>
import { ref } from "vue";
export default {
setup() {
const radioValue = ref("A");
return { radioValue };
},
};
<!-- 단방향 -->
<template>
<div>
<h2>select value</h2>
<select :value="selectValue">
<option value="html">html 수업</option>
<option value="css">css 수업</option>
<option value="javascript">JavaScript 수업</option>
</select>
<div>{{ selectValue }}</div>
</div>
</template>
<!-- 양방향 -->
<template>
<div>
<h2>select value</h2>
<select :value="selectValue" @change=" event => (selectValue = event.target.value)">
<option value="html">html 수업</option>
<option value="css">css 수업</option>
<option value="javascript">JavaScript 수업</option>
</select>
<div>{{ selectValue }}</div>
</div>
</template>
<!-- v-model 양방향 바인딩 -->
<template>
<div>
<h2>select value</h2>
<select v-model="selectValue">
<option value="html">html 수업</option>
<option value="css">css 수업</option>
<option value="javascript">JavaScript 수업</option>
</select>
<div>{{ selectValue }}</div>
</div>
</template>
import { ref } from "vue";
export default {
setup() {
const selectValue = ref("html");
return {
selectValue,
};
},
};
v-model
은 각 input
이벤트 후 입력과 데이터를 동기화 한다. (단, 앞에서 설명한 IME 구성은 제외) lazy
수식어를 추가하여 change
이벤트 이후에 동기화 할 수 있다.<input type="text" v-model="inputValue" />
이럴 때 input에 텍스트를 입력할 때마다 변경되는 값이 계속해서 보여지는데
<input type="text" v-model.lazy="inputValue" />
.lazy
를 사용할 경우 input에 텍스트를 입력 후 포커스가 나갔을 때 변경된 텍스트 값이 보인다.
.number
수식어를 추가하면된다.<input type="text" v-model="inputValue" />
<div>{{ typeof inputValue }}</div>
숫자를 입력했을 때 문자열(string)로 확인이 된다
<input type="text" v-model.number="inputValue" />
<div>{{ typeof inputValue }}</div>
v-model
이 관리하는 input trim
수식어를 추가하면 된다.<input type="text" v-model="inputValue" />
<div>{{ typeof inputValue }}</div>
이렇게 공백을 사용자가 입력하면 데이터에 공백 또한 추가된 걸 볼 수있다. 여기서 .trim
을 사용하면 데이터가 동기화 될 때는 앞 뒤 공백이 제거된 걸 확인할 수 있다.
<input type="text" v-model.trim="inputValue" />
<div>{{ typeof inputValue }}</div>