웹 애플리케이션의 UI는 이를 구성하는 여러 부품의 조합으로 볼 수 있다.
웹 애플리케이션을 잘 관찰해보면 많은 UI 컴포넌트가 문구나 링크 대상등 약간만 차이를 주면 다시 사용할 수 있는 것들이다. 이렇게 재사용이 가능하다는 점이 UI 컴포넌트의 가장 중요한 측면이다.
// 케밥 케이스
components: {
'kebab-fruits-list':{/*...*/}
}
// 파스칼 케이스
components: {
'PascalFruitsList':{/*...*/}
}
케밥 케이스를 적용해 명명한 컴포넌트는 HTML 템플릿에서 그대로 이름을 사용한다.
<kebab-fruits-list></kebab-fruits-list>
파스칼 케이스를 적용해 명명한 컴포넌트는 HTML 템플릿에서 케밥 케이스와 파스칼 케이스 양쪽 모두의 이름을 사용할 수 있다.
<pascal-fruits-list></pascal-fruits-list>
<PascalFruitsList></PascalFruitsList>
두 가지 방법 모두 문제는 없지만, 웹 컴포넌트의 Custom Element 규격의 드래프트를 보면 하이픈으로 연결한 케밥 케이스를 기준으로 하고있다.
또한 Vue.js의 스타일 가이드에서는 여러 개의 단어로 구성된 컴포넌트 이름을 사용하는 것을 추천한다.
Vue.component(컴포넌트명, {
props: {
부모로부터 전달받은 속성명 : {
type: String 혹은 Object 타입,
default: 기본값,
required: 필수 여부,
validator: 유효성 검사 함수
}
}
// ...template 안에서 부모로부터 전달받은 속성 사용 가능
})
부모 컴포넌트에서 자식 컴포넌트에게 props라는 객체를 전달하여 데이터를 사용할 수 있게 한다.
<child-component v-bind:item-name='myItem'></child-component>
자식컴포넌트에게 item-name이라는 props 객체를 전달한 상태이다.
child-component에서는 props로 전달받은 myItem을 본인 컴포넌트에서 item-name으로 사용가능하다.
자식 컴포넌트에서 부모 컴포넌트로 정보를 전달하려면 커스텀 이벤트를 사용한다. Vue 인스턴스에 구현된 이벤트 인터페이스는 다음과 같다.
이벤트는 v-on 디렉티브로도 처리할 수 있다.
용도 | 인터페이스 |
---|---|
이벤트 리스닝 | $on(eventName) |
이벤트 트리거 | $emit(eventName) |
//자식 컴포넌트의 카운터 버튼
var counterButton = Vue.extend({
template: '<span>{{counter}}개<button v-on:click="addToCart">추가</button></span>',
data: function() {
return {
counter: 0
}
},
methods: {
addToCart: function(){
this.counter += 1
this.$emit('increment') //increment 커스텀 이벤트 발생
}
}
})
부모 컴포넌트 쪽에서는 v-on:increment로 increment 이벤트를 기다린다. 그러므로 버튼을 누르면 부모 컴포넌트의 incrementCartStatus() 메서드가 실행될 것이다.
// 부모 컴포넌트 (장바구니)
new Vue({
el: '#fruits-counter',
components: {
'counter-button': counterButton
},
data: {
total:0, //장바구니에 담긴 총 상품 수
fruits: [
{
name:'배'
},
{
name: '딸기'
}
]
},
methods: {
incrementCartStatus: function(){
this.total += 1
}
}
})
<div id="fruits-counter">
<div v-for="fruit in fruits">
<!-- v-on 디렉티브로 커스텀 이벤트를 탐지 -->
{{fruit.name}}
<counter-button v-on:increment="incrementCartStatus()"></counter-button>
</div>
<p>합계: {{total}}</p>
</div>
일부 경우에 속성에 "양방향 바인딩"이 필요할 수 있다.
부모 컴포넌트에서 자식 컴포넌트로 단방향 바인딩이 일반적이지만, 자식 컴포넌트에서 받은 데이터를 변화했을때, 부모 컴포넌트에서도 변화된 값으로 수정한다.
<!-- 자식컴포넌트 -->
<comp v-bind:foo.sync="bar"></comp>
<!-- 위의코드와 아래코드는 동일하다 -->
<comp :foo="bar" @update:foo="var => bar = val"></comp>
하위 컴포넌트가 foo를 갱신하려면 속성을 변경하는 대신 명시적으로 이벤트를 보내야한다.
//<comp :foo="bar" @update:foo="var => bar = val"></comp>의 경우
this.$emit('update:foo', newValue)