컴포넌트간의 양방향바인딩
!! 이 포스트는 vue 버전 2.x
기준으로 작성되었습니다.
최신 vue 3.x 버전에서는 앞으로 소개할 v-model 기능에 많은 변화가 있으니 유의하시기 바랍니다.
컴포넌트간의 props를 “양방향 바인딩” 하는 방법 2가지.
- v-model
- .sync
v-model
v-model 속성은 v-bind와 v-on의 기능의 조합으로 동작합니다. 매번 사용자가 일일이 v-bind와 v-on 속성을 다 지정해 주지 않아도 좀 더 편하게 개발할 수 있게 고안된 문법입니다.
<input v-model="inputText"/>
new Vue({
data: {
inputText: ''
}
})
위 아래 코드는 같은 역할을 하는 코드 입니다 ===
<input v-bind:value="inputText" v-on:input="updateInput"/>
new Vue({
data: {
inputText: ''
},
methods: {
updateInput: function(event) {
var updatedText = event.target.value;
this.inputText = updatedText;
}
}
})
v-bind
속성은 뷰 인스턴스의 데이터 속성을 해당 HTML 요소에 연결할 때 사용한다.v-on
속성은 해당 HTML 요소의 이벤트를 뷰 인스턴스의 로직과 연결할 때 사용한다.- 사용자 이벤트에 의해 실행된 뷰 메서드(methods) 함수의 첫 번째 인자에는 해당 이벤트(
event
)가 들어온다.
HTML 입력 요소의 종류에 따라 `v-model` 속성이 각각 다음과 같이 구성됩니다.
(1) input 태그에는 `value / input`
(2) checkbox 태그에는 `checked / change`
(3) select 태그에는 `value / change`
기존 방법 ( v-model)
parent component
<div class="inputArea">
<CTextarea v-model="hostingContent" />
</div>
CTextarea.component
<template>
<textarea :value="value" @input="inputChange"></textarea>
</template>
<script>
export default {
name: "input",
props: ["value"],
data() {
return {};
},
methods: {
inputChange(event) {
this.$emit("input", event.target.value);
},
},
};
</script>
- 코드에서 알 수 있듯이 상위 컴포넌트에서 props을 기본값으로 ‘value’ 라는 명으로 받아옵니다.
- 인풋 태그에서 값이 입력되면 인풋 태그에서 input 이벤트가 발생하고 inputChange 메서드가 실행됩니다.
- updateInput 메서드에서 인풋 태그에 입력된 값을 상위 컴포넌트에 input 이벤트로 올려 보냅니다.
model 옵션
value 속성을 다른 용도로 사용하여야 하는 경우에는 model 옵션을 이용하여 문제가 생기는 것을 방지할 수 있습니다.
CTextarea.component
<template>
<textarea :value="testValue" @input="inputChange"></textarea>
</template>
<script>
export default {
name: "input",
model: {
prop: "testValue",
event: "input",
},
props: ["testValue"],
data() {
return {};
},
methods: {
inputChange(event) {
this.$emit("input", event.target.value);
},
},
};
</script>
.sync
- 2.3.0+ 에서 추가된 기능입니다.
v-model
과.sync
의 명백한 차이점은 구문입니다. 컴포넌트가 어떻게 표시되는지 확인해봅시다.
parent
<div class="inputArea">
<CTextarea :hostingContent.sync="hostingContent" />
</div>
CTextarea.component
<template>
<textarea
:value="hostingContent"
@input="$emit('update:hostingContent', $event.target.value)"
></textarea>
</template>
<script>
export default {
name: "input",
props: ["hostingContent"],
data() {
return {};
},
methods: {
/*
inputChange(event){
this.$emit('input', event.target.value);
}
*/
},
};
</script>
.sync 를 사용할때는 자식 컴포넌트는 value prop이 필요하지 않습니다. 대신 부모와 동일한 prop 이름을 사용하면 됩니다.
최종 예제 ( 팝업 )
parent
<transition name="pop">
<ItemDeletePopShare v-if="deletePopFlag" :deletePopFlag.sync="deletePopFlag" @closeShare="requestChangeThumbNail" :getItemType="getItemType" :getItemProps="getItemProps" />
</transition>
child
<template>
<div class="layerPop2" id="writingDelPop">
<p class="popblackBg"></p>
<div class="popBody">
<div class="layCon">
<div class="writingDelDiv">게시글 비공개를 하시겠습니까?</div>
<a class="delete_btn" @click="$emit('closeShare')">확인</a>
<a
id="cancel_btn2"
class="cancel_btn2"
@click="$emit('update:deletePopFlag', false)"
>취소</a
>
</div>
</div>
</div>
</template>
<script>
import myMixin from "@/mixin/mixin";
import { mapGetters } from "vuex";
export default {
name: "ItemDeletePop",
mixins: [myMixin],
computed: {
...mapGetters(["memberInfo"]),
},
props: {
getItemType: Function,
getItemProps: Function,
deletePopFlag: Boolean,
requestChangeThumbNail: Function,
},
data() {
return {};
},
methods: {},
};
</script>
- 자식컴포넌트에게 v-if 를 통해 렌더 여부를 boolean 타입으로 설정
- 자식컴포넌트에게 :deletePopFlag.sync=”deletePopFlag” 로 prop 전달
-
자식컴포넌트는 전달받은
'deletePopFlag'
을 팝업을 해제하는 버튼에 양방향 컨트롤로 사용<a id="cancel_btn2" class="cancel_btn2" @click="$emit('update:deletePopFlag', false)">취소</a>
마치며
해당 글에서 소개하는 기능은 2.x 버전을 기준으로 작성하였습니다. 오늘날에는 vue 버전이 3.x 으로 업그레이드 되면서 많은 기능들이 추가되고 바뀌었습니다. 그 중 v-model 또한 많은 업데이트가 있었고 앞서 소개드린 .sync 기능도 삭제되었습니다. 이점 유의하시기 바랍니다.
- references:
- Written by: 박상길 (fkdl3919@gmail.com)
- reporting date: 2021-05-16