props
가 아닌 속성props
가 아닌 속성은 컴포넌트로 전달되지만 props
로는 정의되지 않은 속성이다.
명시적으로 정의된 props
는 하위 컴포넌트에 정보를 전달하는데 쓰이지만,
컴포넌트 라이브러리 작성자는 컴포넌트가 사용될 수 있는 상황을 항상 예측할 수 없기 때문에,
컴포넌트는 임의의 속성을 추가할 수 있다.
예를 들어, childComp
컴포넌트에 add-something-attr
라는 임의의 속성을 추가할 수 있는 것이다.
<childComp add-something-attr="true"></childComp>
그러면 add-something-attr="true"
속성는 자동으로 childComp
컴포넌트에 추가된다.
다음 소스가 childComp
이라는 템플릿이라고 가정했을 때
<div class="child-original"></div>
childComp
컴포넌트에게 다음과 같은 특정 클래스를 추가한다면
<childComp
class="parent-add"
></childComp>
이 경우, 2개의 다른 값이 class 정의되는 것이다.
child-original
: 템플릿 내에서 설정한 classparent-add
: 부모에 의해 컴포넌트에 전달되는 class대부분의 속성의 경우 컴포넌트에 제공된 값이 컴포넌트에 의해 설정된 값을 대체한다.
예를 들어, type="date"
속성에 type="text"
가 전달되면 속성 값이 대체돼 버려 망가지게 되는 것이다.
다행히 class와 style은 예외로 두 값이 합쳐지기 때문에
최종 class는 class="child-original parent-add"
이 된다.
v-on
을 이용한 사용자 정의 이벤트$emit
을 이용한 자식 컴포넌트에서 부모 컴포넌트로 데이터를 전달모든 Vue 인스턴스는 다음과 같은 이벤트 인터페이스를 구현한다.
v-on
을 사용하여 자식 컴포넌트에서 보내진 이벤트를 청취할 수 있다.// 자식 컴포넌트
Vue.component('childComp', {
template: '<button v-on:click="childMethod">{{ counter }}</button>',
data: function () {
return {
counter: 0
}
},
methods: {
childMethod: function () {
this.counter += 1
this.$emit('vOnEventName')
}
},
})
<!-- 부모 컴포넌트 -->
<div id="parentComp">
<p>{{ total }}</p>
<childComp v-on:vOnEventName="parentMethod"></childComp>
<childComp v-on:vOnEventName="parentMethod"></childComp>
</div>
// 부모 컴포넌트
new Vue({
el: '#parentComp',
data: {
total: 0
},
methods: {
parentMethod: function () {
this.total += 1
}
}
})
.sync
일부 경우 양방향 바인딩이 필요할 수 있다.
자식 컴포넌트가 .sync
를 가지는 속성을 변경하면 값의 변경이 부모에 반영된다.
편리하지만 단방향 데이터 흐름이 아니기 때문에 장기적으로 유지보수에 문제가 생길 수 있다.
자식 속성을 변경하는 코드는 부모의 상태에 영향을 미친다.
// 자식 컴포넌트
this.$emit('update:syncEventName', this.counter);
<!-- 부모 컴포넌트 -->
<comp :syncEventName.sync="bar"></comp>
<!-- ↑ 같은 거 ↓ -->
<comp :syncEventName="bar" @syncEventName:foo="val => bar = val"></comp>
<!-- ❕v-model의 작동원리❕ -->
<input v-model="something">
<!-- ↑ 같은 거 ↓ -->
<input v-bind:value="something" v-on:input="something = $event.target.value">
사용자 정의 이벤트는 v-model
에서 작동하는 사용자 정의 입력을 만드는 데에도 사용할 수 있다.
<custom-input :value="something" @input="value => { something = value }"></custom-input>
따라서 v-model을 사용하는 컴포넌트는
기본적으로 컴포넌트의 v-model은 value를 보조 변수로 사용하고 input을 이벤트로 사용하지만
체크 박스와 라디오 버튼과 같은 일부 입력 타입은 다른 목적으로 value 속성을 사용할 수 있다.
model 옵션을 사용하면 다음 경우에 충돌을 피할 수 있다.
Vue.component('base-checkbox', {
model: {
prop: 'checked',
event: 'change'
},
props: {
checked: Boolean
},
template: `
<input
type="checkbox"
v-bind:checked="checked"
v-on:change="$emit('change', $event.target.checked)"
>
`
})
<base-checkbox v-model="foo"></base-checkbox>
<!-- ↑ 같은 거 ↓ -->
<base-checkbox
:checked="foo"
@change="val => { foo = val }">
</base-checkbox>
때로는 두 컴포넌트가 서로 통신해야 하지만 서로 부모∙자식이 아닐 경우가 있다.
간단한 시나리오에서는 비어있는 Vue 인스턴스를 중앙 이벤트 bus로 사용할 수 있다.
var bus = new Vue()
// 컴포넌트 A의 메소드
bus.$emit('id-selected', 1)
// 컴포넌트 B의 created 훅
bus.$on('id-selected', function (id) {
// ...
})