[Vue.js] 새로운 v-model 살펴보기#4 ($attrs, $listeners)
하수도키
·2021. 2. 7. 16:18
728x90
반응형
SMALL
2021/01/22 - [개발일기/Vue.js] - [Vue.js] 새로운 v-model 살펴보기#1 (vue3에서 바뀐 점)
2021/01/28 - [개발일기/Vue.js] - [Vue.js] 새로운 v-model 살펴보기#2 (다수의 v-model 사용하기)
2021/01/31 - [개발일기/Vue.js] - [Vue.js] 새로운 v-model 살펴보기#3 (v-model custom modifiers)
- 이번 포스팅에서는
$attrs
가 vue3에서 어떻게 변했는지 살펴보자. - vue2에서는 HTML attributes들만 포함했지만 vue3에서는 HTML attributes뿐 아니라 listeners, classes, styles까지 다 포함한다.
- 이러한 개념을 배우면서 부모에서 자식 컴포넌트로 event, attributes들이 어떻게 전달되는지도 알아보자.
Vue 2, Vue 3에서 $attrs
비교하기(Differences between Vue 2 and Vue 3 in $attrs)
- Vue 2에서는
$attrs
은 부모가class, style
를 제외하고 모든 속성들을 자식에게 넘겨주는 컴포넌트 데이터의 속성이다. 또한 자식에서 부모에게 전달되는 이벤트를 모아놓은$listeners
객체도 있다.
// Vue 2
<BaseInput
@click="handleClick"
@custom="handleCustom"
v-model="value"
type="button"
class="btn"
/>
// Inside BaseInput.vue
$listeners = {
click: handleClick,
custom: handleCustom,
input: () => {}
}
$attrs = {
type: 'button'
}
- Vue 3에서는
$listeners
가 없어졌고$attrs
안으로 이벤트들이 존재한다.
// Vue 3
<BaseInput
@click="handleClick"
@custom="handleCustom"
v-model="value"
type="button"
class="btn"
/>
// Inside BaseInput.vue
$attrs = {
class: 'btn'
type: 'button',
onClick: handleClick,
onCustom: handleCustom,
'onUpdate:modelValue': () => { value = payload },
}
- Vue 2와는 달리
on
prefix가 이벤트에 붙었다. 그리고 Vue 3v-model
로직인onUpdate:modelValue
가 Vue 2와는 다르다. - 그리고 여기는 HTML 모든 속성들이 담겨진다. (
class, style, id, aria, col, row, type, src 등
)
컴포넌트에 $attrs
연결하기(Binding $attrs to a component)
BaseInput
이라는div
로label, input
을 감싸는 컴포넌트를 만들면서 살펴보자.(예전 포스팅에서 만든 예제이다.)
// BaseInput.vue
<template>
<div>
<label>{{ label }}</label>
<input
:value="modelValue"
@input="$emit('update:modelValue', $event.target.value)"
/>
</div>
</template>
<script>
export default {
props: {
modelValue: {
type: [String, Number],
default: ''
},
label: {
type: String,
default: null
}
}
}
</script>
- 위에 만든
BaseInput
컴포넌트를App.vue
에 바로 사용해보자.
// App.vue
<template>
<div id="app">
<BaseInput
v-model="email"
label="Email:"
type="email"
/>
<pre>{{ email }}</pre>
</div>
</template>
<script>
import { ref } from 'vue'
import BaseInput from './components/BaseInput'
export default {
name: 'App',
components: {
BaseInput
},
setup () {
const email = ref('')
return {
email
}
}
}
</script>
BaseInput
에 input type을email
로 지정하기위해type
을 내려준다.- 아래 이미지를 보게되면
input
태그에 선언되지 않고 부모div
태그에 선언된 것을 볼 수 있다. Vue 2랑 같은 현상이다.
class
도 마찬가지다.
<BaseInput
v-model="email"
label="Email:"
type="email"
class="thicc"
/>
- 이제
$attrs
를 사용해서 제대로input
태그에 선언해보자.
// BaseInput.vue
<template>
<div>
<label>{{ label }}</label>
<input
v-bind="$attrs"
:value="modelValue"
@input="$emit('update:modelValue', $event.target.value)"
/>
<pre>{{ $attrs }}</pre>
</div>
</template>
v-bind="$attrs"
코드를 추가하면input
태그에 속성들이 선언된다.
- 위 이미지와 같이
type
과class
둘다input
에 선언된다. - Vue 2에서는
input
에class
와style
은 선언되지 않지만 Vue 3에서는input
에 즉,$attrs
를 사용하는 곳에 선언된다. - 하지만, 아직도 부모
div
에도 같이 적용되고 있으니 이걸 없애보자.
export default {
inheritAttrs: false,
props: {
modelValue: {
type: [String, Number],
default: ''
},
label: {
type: String,
default: null
}
}
}
inheritAttrs: false
이걸 추가하면 부모가$attrs
를 상속받지 않는다.
$attrs
를 이용해 listeners
를 연결하자.(Binding listeners thorugh our $attrs
)
- 지금까지
$attrs
를 사용해 속성들을 바인딩했다. 이제listeners
를 바인딩해보자. - 현재
input
event는input
엘리먼트에 잘 연결되어있지만 만약 다른native input event
를 바인딩하고 싶은 경우 살펴보자. - 예를 들면 아래과 같이
@blur
이벤트를 바인딩 하고 싶을 경우
// App.vue
<BaseInput
v-model="email"
@blur="email = 'blurrr@its.cold'"
label="Email:"
type="email"
class="thicc"
/>
- Vue 2에서는
v-on="$listeners"
를 사용해 이벤트를 바인딩해줬찌만 Vue 3에선느 위에서 사용한$attrs
에 모두 포함되어있으므로 별도로 처리할 필요가 없다.
BaseInput 리팩토링(input
이벤트 리팩토링)
$attrs
에 모든 이벤트들이 있지만input
만 따로 선언되어 사용중이다.input
을onInput
으로 리팩토링해보자.$attrs
는Object
이므로 스프레드 연산자 사용이 가능하므로 아래와 같이 수정해보자.
// BaseInput.vue
<input
v-bind="{
...$attrs,
onInput: (event) => $emit('update:modelValue', event.target.value)
}"
:value="modelValue"
/>
- 코드가 더 명확하고 깔끔해졌고,
input
과 같은 특정이벤트가 부모 컴포넌트에 의해 다시 덮어씌여질 위험도 없어졌다.(부모가@input
이런걸 사용하지 않아도 되니까??)
결론
$attrs
,$listeners
에 대한 개념이 부족해서 설명이 매끄럽지 못했지만, 자주 보면서 좀 더 공부하고 수정해 나가야 될것 같다.- Vue 2보다 확실히 Vue 3가 많이 편해진 것 같다.
728x90
반응형
LIST
'개발일기 > Vue.js' 카테고리의 다른 글
[Vue.js] Vue3+Typescript #1 - Vue, TypeScript 사용하는 이유(Why Vue & TypeScript) (0) | 2021.03.05 |
---|---|
[Vue.js] 새로운 v-model 살펴보기#5(Multi root components) (0) | 2021.03.01 |
[Vue.js] 새로운 v-model 살펴보기#3 (v-model custom modifiers) (2) | 2021.01.31 |
[Vue.js] 새로운 v-model 살펴보기#2 (다수의 v-model 사용하기) (0) | 2021.01.28 |
[Vue.js] 새로운 v-model 살펴보기#1 (vue3에서 바뀐 점) (0) | 2021.01.22 |