2025. 3. 30. 21:05ㆍFront-End/Vue.js
Vue에서 컴포넌트를 설계하다 보면, 특정 위치에 외부에서 콘텐츠를 끼워 넣고 싶을 때가 있다. 이런 경우 slot을 사용하면 컴포넌트의 내부 구조는 유지하면서 다양한 콘텐츠를 유연하게 전달할 수 있다.
기본 슬롯
가장 단순한 형태의 슬롯은 <slot></slot>이다. 부모 컴포넌트에서 전달한 콘텐츠가 이 자리에 삽입된다.
<!-- BaseButton.vue -->
<template>
<button class="primary">
<slot></slot>
</button>
</template>
<!-- App.vue -->
<template>
<BaseButton>
확인
</BaseButton>
</template>
결과
<button class="primary">
확인
</button>
전달할 수 있는 콘텐츠는 텍스트뿐 아니라 HTML 요소, 다른 컴포넌트 등 어떤 것이든 가능하다.
<BaseButton>
<strong>확인</strong> <span>✔️</span>
</BaseButton>
폴백 콘텐츠
슬롯에 콘텐츠가 전달되지 않은 경우를 대비해 기본값(폴백)을 지정할 수 있다.
<!-- BaseButton.vue -->
<template>
<button>
<slot>기본 버튼</slot>
</button>
</template>
이렇게 하면 슬롯 콘텐츠가 없을 때 "기본 버튼"이 출력된다.
이름이 있는 슬롯 (Named Slots)
복잡한 컴포넌트에서 여러 위치에 서로 다른 콘텐츠를 전달하려면 이름 있는 슬롯을 사용한다.
<!-- CardLayout.vue -->
<template>
<section class="card">
<header>
<slot name="header"></slot>
</header>
<div class="content">
<slot></slot> <!-- default slot -->
</div>
<footer>
<slot name="footer"></slot>
</footer>
</section>
</template>
사용 예시:
<CardLayout>
<template #header>
<h1>공지사항</h1>
</template>
<p>내용을 입력해주세요.</p>
<template #footer>
<small>ⓒ 2025</small>
</template>
</CardLayout>
- #header, #footer는 v-slot:header, v-slot:footer의 축약형
- 이름이 없는 슬롯은 default 슬롯이며, 암시적으로 전달된다
default 슬롯의 암시적 전달
아래 예시는 default 슬롯을 명시하지 않고도 콘텐츠를 전달하는 방식이다.
<CardLayout>
<template #header>헤더</template>
본문 내용입니다.
<template #footer>푸터</template>
</CardLayout>
"본문 내용입니다."는 default 슬롯으로 자동 인식된다.
동적 슬롯 이름
슬롯 이름을 변수로 동적으로 설정할 수 있다.
<CardLayout>
<template v-slot:[currentSlot]>
동적 슬롯 콘텐츠
</template>
</CardLayout>
변수 currentSlot의 값에 따라 다른 슬롯에 콘텐츠가 들어간다.
슬롯의 렌더링 범위
기본적으로 슬롯 콘텐츠는 부모 컴포넌트의 데이터에만 접근할 수 있고, 자식 컴포넌트의 데이터는 접근할 수 없다.
<CardLayout>
{{ parentData }} <!-- 가능 -->
{{ childInternalValue }} <!-- ❌ 불가능 -->
</CardLayout>
Scoped Slots (자식 → 부모 데이터 전달)
자식 컴포넌트의 데이터를 부모 슬롯 콘텐츠로 전달하고 싶을 때는 Scoped Slot을 사용한다.
<!-- InfoBox.vue -->
<template>
<div>
<slot :message="infoMessage" :status="status"></slot>
</div>
</template>
<script>
import { ref } from 'vue';
export default {
setup() {
const infoMessage = ref('데이터가 준비되었습니다');
const status = ref('success');
return { infoMessage, status };
}
};
</script>
<!-- App.vue -->
<InfoBox v-slot="{ message, status }">
<p>{{ message }} - 상태: {{ status }}</p>
</InfoBox>
- 자식 컴포넌트는 <slot :속성="값">으로 데이터를 전달
- 부모 컴포넌트는 v-slot="{ 속성명 }"으로 데이터를 받음
Named Scoped Slot
이름이 있는 슬롯에도 Scoped Slot 방식을 사용할 수 있다.
<!-- App.vue -->
<InfoBox>
<template #header="{ message }">
<h3>{{ message }}</h3>
</template>
<template #default="{ status }">
<p>현재 상태: {{ status }}</p>
</template>
</InfoBox>
- 각 슬롯에 필요한 데이터를 선택적으로 전달받아 사용할 수 있다
정리
구분 설명
기본 슬롯 | 콘텐츠를 자식 컴포넌트 내부로 전달하는 가장 단순한 형태 |
폴백 콘텐츠 | 슬롯 콘텐츠가 없을 때 출력될 기본값 |
이름 있는 슬롯 | 여러 위치에 다양한 콘텐츠 전달 가능 |
Scoped Slot | 자식 컴포넌트에서 데이터를 부모 슬롯 콘텐츠로 전달 |
Named Scoped Slot | 이름 있는 슬롯에서도 scoped 방식 사용 가능 |
슬롯 범위 | 기본적으로 부모의 데이터에만 접근 가능, 자식 데이터는 scoped 방식으로만 가능 |
슬롯은 컴포넌트의 확장성과 유연성을 크게 높여주는 기능이다.
단순히 컴포넌트의 콘텐츠를 바꾼다는 수준을 넘어서, 자식 → 부모 방향 데이터 전달까지도 가능하게 해주기 때문에 컴포넌트를 좀 더 재사용 가능하게 만드는 핵심적인 기능 중 하나라고 볼 수 있다.
'Front-End > Vue.js' 카테고리의 다른 글
Vue 3 – 컴포넌트 라이프사이클과 훅 정리 (0) | 2025.03.30 |
---|---|
Vue 3 – Provide / Inject로 깊은 컴포넌트 간 데이터 전달하기 (0) | 2025.03.30 |
Vue 3 - Non-Prop 속성 제대로 이해하기 (0) | 2025.03.30 |
Vue 3 – 이벤트(emit)로 컴포넌트 간 데이터 전달하기 (0) | 2025.03.30 |
Vue 3 – Props로 컴포넌트에 데이터 전달하기 (0) | 2025.03.30 |