Slot 과 v-slot 기능 포스팅
Vue 개발 중 공부내용을 기록하는 포스트 입니다.
1. 개요
간단한 TodoList
를 Vue
로 개발하면서 slot
의 기능에 대해서 다시한번 정리해본다.
2. 구성
- todoProject
... 생략
- src
... 생략
- App.js
- components
... 생략
- TodoInput.vue
- common
- Modal.vue
2-1. App.js
우선 구성은 App.js
는 Container Component
의 역할을 한다.
모든 상태관리는 App.js
에서 이뤄지고 components
폴더 내 ToDoList, TodoInput, TodoHeader ...
등등의 Presentational Component
에서는 변경 해달라고 emit
을 통해서 요청을 하는 형태이다.
2-2. TodoInput.vue
TodoInput.vue
컴포넌트에서 이번에 볼 부분은 slot
을 사용한 부분이다.
<!-- Modal.vue -->
<transition name="modal">
<div class="modal-mask">
<div class="modal-wrapper">
<div class="modal-container">
<div class="modal-header">
<slot name="header"> default header </slot>
</div>
<div class="modal-body">
<slot name="body"> default body </slot>
</div>
<div class="modal-footer">
<slot name="footer">
default footer
<button class="modal-default-button" @click="$emit('close')">
OK
</button>
</slot>
</div>
</div>
</div>
</div>
</transition>
<!-- TodoInput.vue -->
<!-- ... 생략 -->
<Modal v-if="showModal" @close="showModal = false">
<!--
you can use custom content here to overwrite
default content
-->
<h3 slot="header">경고!</h3>
</Modal>
<!-- ... 생략 -->
여기서 TodoInput.vue
는 Modal.vue
의 부모 컴포넌트가 된다.
Modal.vue
에서 <slot name="header">
를 통해 default header
로 slot
을 먼저 정의해 놓았고 우리는 이러한 Modal.vue
를 사용하면서 사용자의 재정의
가 가능한 것이다.
위에 이미지에서 보이듯이 우리가 TodoInput.vue
에서 재정의한 header
부분만 다르게 나타난다.
3. slot-scope
slot
을 통해서 자식 컴포넌트에서 사용된 데이터 혹은 메서드를 사용할 수도 있다.
아래의 예제를 보자
<!-- 자식 컴포넌트 -->
<!-- ... 생략 -->
<div class="modal-body">
<slot name="body" :modalData="modalData" :consoleMessage="consoleMessage">
default body
</slot>
</div>
<script>
export default {
data() {
return {
modalData: ["modalData1", "modalData2"],
};
},
methods: {
consoleMessage() {
console.log("Console Message!");
},
},
};
</script>
<!-- ... 생략 -->
<!-- 부모 컴포넌트 -->
<!-- ... 생략 -->
<Modal v-if="showModal" @close="showModal = false">
<!--
you can use custom content here to overwrite
default content
-->
<h3 slot="body" slot-scope="slotScope">
<button v-on:click="slotScope.consoleMessage">Console Button</button>
</h3>
</Modal>
<!-- ... 생략 -->
위 소스에서 보면 Child Component
에서 body Slot
에서 modalData
와 consoleMessage
메서드를 정의하고 Parent Component
에서 사용되는걸 볼 수 있다.
그리고 Console Button
을 클릭하면 Child Component
에서 정의한 ConsoleMessage
함수가 실행되어 console
메시지가 찍히는걸 볼 수 있다.
3-1. v-slot
Vue3
에서는 slot
, slot-scope
가 공식적으로 삭제 된다고 한다.
같은 기능을 제공하는 Vue
디렉티브 v-slot
로 동일한 기능을 구현해보자.
child Component
는 동일하고 Parent Component
에 변화가 생긴다.
<!-- 부모 컴포넌트 -->
<!-- slot-scope 사용 -->
<Modal v-if="showModal" @close="showModal = false">
<!--
you can use custom content here to overwrite
default content
-->
<h3 slot="body" slot-scope="slotScope">
<button v-on:click="slotScope.consoleMessage">Console Button</button>
</h3>
</Modal>
<!-- v-slot 사용 -->
<Modal v-if="showModal" @close="showModal = false">
<!--
you can use custom content here to overwrite
default content
-->
<template v-slot:body="slotProps">
<h3>
<button v-on:click="slotProps.consoleMessage">Console Button</button>
</h3>
</template>
</Modal>
v-slot
을 사용할 때는 v-slot:[name]
으로 사용하고 template
태그로 감싸고 그 안에서 사용해야 한다는 점이 차이가 있다.
slot
의 기능은 실무에서도 자주 쓰이기 때문이 이번 Modal
을 진행하면서 다시한번 리마인드 겸 정리하도록 하였다.
최종 적용예
하나의 예를 더 진행한다.
상위 컴포넌트 : UserView, ItemView
하위 컴포넌트 : UserProfile.vue
UserView
, ItemView
두개의 컴포넌트에서 하나의 컴포넌트
를 재사용 하는 경우이다.
하지만, 각각의 상위 컴포넌트에서 데이터
를 props
로 내려주는 방식으로 진행했을 때 각각의 경우마다 분기처리 해줘야되는 번거로움이 생긴다.
이럴경우 slot
을 활용해서 상위 컴포넌트
에서 하위 컴포넌트
에 들어갈 내용을 정의하면 된다.
그렇게되면 상위 컴포넌트
에서 가지고 있는 데이터로 재사용된 컴포넌트를 채울 수 있기 때문이다 아래 코드를 보자.
<!-- 상위 컴포넌트(UserView) -->
<template>
<div>
<user-profile :itemInfo="itemInfo">
<div slot="username"></div>
<template slot="time"></template>
</user-profile>
</div>
</template>
<!-- 상위 컴포넌트(ItemView) -->
<div>
<section>
<!-- 질문 상세 정보 -->
<user-profile :itemInfo="itemInfo">
<div slot="username"></div>
<template slot="time"></template>
</user-profile>
<section>
<h2></h2>
</section>
</section>
<!-- 하위 컴포넌트(UserProfile) -->
<template>
<div>
<user-profile :itemInfo="itemInfo">
<div slot="username"></div>
<template slot="time"></template>
</user-profile>
</div>
</template>
</div>
위와 같이 하위 컴포넌트
에서 실제로 필요한 위치에 각각의 name
을 갖는 slot
태그를 만들었다.
이후 상위 컴포넌트의 재사용하는 user-profile
태그에 각각의 용도에 맞춰 name
프로퍼티를 넣고 실제 들어가야할 tag
를 정의한다.
작은거라도 하나하나 정리해가다보면 점점 내것이 되는것 같아 기분이 좋다.