이전 포스팅에 이어 뷰의 컴포넌트의 정의, 유효범위 및 사용법에 대해 알아보도록 한다.
컴포넌트(Component)
란 조합하여 화면을 구성할 수 있는 블록을 의미하며 다음과 같은 장점을 지닌다.
컴포넌트를 등록할 때, 전역
과 지역
두 가지 방법으로 가능하다.
지역(Local)
컴포넌트는 특정 인스턴스에서만 유효한 범위를, 전역(Global)
컴포넌트는 여러 인스턴스에서 공통으로 사용할 수 있다.
전역 컴포넌트는 다음과 같이 Vue
변수를 이용하여 등록하며, .component()
함수를 호출하여 실행한다.
<html>
<head>
<title>Vue Component Registration</title>
</head>
<body>
<div id="app">
<button>컴포넌트 등록</button>
<my-component></my-component>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.2/dist/vue.js"></script>
<script>
Vue.component('my-component', {
template: '<div>전역 컴포넌트가 등록되었습니다!</div>'
});
new Vue({
el: '#app'
});
</script>
</body>
</html>
위의 my-component 태그부분은 최종적으로 다음과 같이 변경된다.
<div id="app">
<button>컴포넌트 등록</button>
<!-- 치환된 모습 -->
<div>전역 컴포넌트가 등록되었습니다!</div>
</div>
지역 컴포넌트는 인스턴스에 component
속성을 추가하여 이름과 내용을 정의한다.
...
<script>
var cmp = {
// 컴포넌트 내용
template: '<div>지역 컴포넌트가 등록되었습니다!</div>'
};
new Vue({
el: '#app',
components: {
'my-local-component': cmp
}
});
</script>
<html>
<head>
<title>Vue Local and Global Components</title>
</head>
<body>
<div id="app">
<h3>첫 번째 인스턴스 영역</h3>
<my-global-component></my-global-component>
<my-local-component></my-local-component>
</div>
<hr>
<div id="app2">
<h3>두 번째 인스턴스 영역</h3>
<my-global-component></my-global-component>
<my-local-component></my-local-component>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.2/dist/vue.js"></script>
<script>
// 전역 컴포넌트 등록
Vue.component('my-global-component', {
template: '<div>전역 컴포넌트 입니다.</div>'
});
// 지역 컴포넌트 내용
var cmp = {
template: '<div>지역 컴포넌트 입니다.</div>'
};
new Vue({
el: '#app',
// 지역 컴포넌트 등록
components: {
'my-local-component': cmp
}
});
// 두 번째 인스턴스
new Vue({
el: '#app2'
});
</script>
</body>
</html>
위와 같은 코드에서 첫번째 인스턴스 영역에서는 전역, 지역이 모두
표기되나 두번째 인스턴스에서는 전역
만 노출된다.
전역 컴포넌트는 인스턴스를 새로 생성할 때마다, 인스턴스에 components 속성으로 등록할 필요 없이 사용 가능하나,
지역 컴포넌트는 새 인스턴스를 사용할 때마다 등록해줘야 한다.
뷰 컴포넌트는 자체적으로 고유한 유효 범위(Scope)
을 지니기 때문에 같은 웹 페이지에 존재하더라도, 데이터 공유가 불가능
하다.
따라서 뷰 프레임워크 자체에서 정의한 컴포넌트 데이터 전달 방법을 따라야 하는데, 가장 기본적인 방법은 상위-하위
컴포넌트 간의 데이터전달이다.
기본적으로 상위 -> 하위
로는 props
라는 특별한 속성을 전달하고, 하위 -> 상위
로는 이벤트
만 전달이 가능하다.
상위 -> 하위
컴포넌트로 데이터를 전달할 때는 props
라는 속성을 다음과 같은 순서로 사용한다.
props
를 정의v-bind
속성을 추가이를 코드로 나타내면 다음과 같다.
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Vue Props Sample</title>
</head>
<body>
<div id="app">
<!-- 팁 : 오른쪽에서 왼쪽으로 속성을 읽으면 더 수월합니다. -->
<child-component v-bind:propsdata="message"></child-component>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.2/dist/vue.js"></script>
<script>
Vue.component('child-component', {
props: ['propsdata'],
template: '<p>{ { propsdata }}</p>',
});
new Vue({
el: '#app',
data: {
message: 'Hello Vue! passed from Parent Component'
}
});
</script>
</body>
</html>
하위 -> 상위
컴포넌트의 통신은 이벤트(Event)
를 발생시켜 신호를 보내는 방식으로 작동한다.
이를 처리하기 위해 상위 컴포넌트는 이벤트를 기다리고 있다가 하위 컴포넌트에서 특정 이벤트가 발생하면,
상위 컴포넌트에서 해당 이벤트를 수신하여 상위 컴포넌트의 메서드
를 호출한다.
뷰 공식 사이트에서 이벤트 발생 사용방법에서는 하위 -> 상위 컴포넌트로 데이터의 전달은 다루지 않는다고 한다.
뷰의 단방향 데이터 흐름에 어긋나는 방법이기 때문인데, 복잡한 어플리케이션에서는 전달해야할 경우가 생기게 된다.
이를 위한 방법이이벤트 버스(Event Bus)
이다.
이벤트 발생과 수신은 $emit()
과 v-on:
속성을 사용하여 구현하며, 이를 코드로 나타내면 다음과 같다.
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Vue Event Emit Sample</title>
</head>
<body>
<div id="app">
<child-component v-on:show-log="printText"></child-component>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.2/dist/vue.js"></script>
<script>
Vue.component('child-component', {
template: '<button v-on:click="showLog">show</button>',
methods: {
showLog: function() {
this.$emit('show-log');
}
}
});
new Vue({
el: '#app',
data: {
message: 'Hello Vue! passed from Parent Component'
},
methods: {
printText: function() {
console.log("received an event");
}
}
});
</script>
</body>
</html>
$emit()
을 호출하면 괄호안에 정의된 이벤트가 발생되며, 해당 이벤트 명을 v-on:
속성에지정하고 발생시킬 메서드를 지정한다.
기본적인 통신 규칙을 지키며 동레벨의 컴포넌트에게 데이터를 전달하기 위해서는, 해당 컴포넌트들의 공통 상위 컴포넌트
를 통해 전달해야 한다.
즉, 하위 컴포넌트1 -> 공통 상위 컴포넌트 -> 하위 컴포넌트2의 방식으로 전달되야 하는데, 이를 해결하기 위한 방법이 이벤트 버스
이다.
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Vue Event Bus Sample</title>
</head>
<body>
<div id="app">
<child-component></child-component>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.2/dist/vue.js"></script>
<script>
var eventBus = new Vue();
Vue.component('child-component', {
template: '<div>하위 컴포넌트 영역입니다.<button v-on:click="showLog">show</button></div>',
methods: {
showLog: function() {
eventBus.$emit('triggerEventBus', 100);
}
}
});
var app = new Vue({
el: '#app',
created: function() {
eventBus.$on('triggerEventBus', function(value){
console.log("이벤트를 전달 받음. 전달 받은 값 : ", value);
});
}
});
</script>
</body>
</html>
위 코드는 show 버튼을 클릭했을 때, 이벤트 버스를 이용하여 상위 컴포넌트로 데이터를 전달하는 코드이며 다음과 같은 흐름으로 진행된다.
eventBus
의 이벤트 발생eventBus.$on()
에서 전달 받음위와 같이 이벤트 버스를 활용하면 props 속성을 이용하지 않고 원하는 컴포넌트 간의 데이터 교환이 가능하다.
하지만 컴포넌트가 많아지면, 어디서 어디로 보내는지관리가 되지 않는 문제점
이 발생한다.
이 문제를 해결하기 위해서는Vuex
라는 상태 관리 도구가 필요하다.
여태까지 뷰의 기본적인 개요 및 인스턴스와 컴포넌트에 대하여 알아보았다.
다음 포스팅에서는 뷰의 라우터
와 HTTP
통신 방법에 대하여 알아보자.