- 슬롯은 템플릿 조각을 자식 컴포넌트에 전달하여 자식 컴포넌트가 자체 템플릿 내에서 조각을 렌더링하는 것이다.
<FancyButton>
클릭하기!
</FancyButton>
<button class="fancy-btn">
<slot></slot>
</button>
<button class="fancy-btn">클릭하기!</button>
1. 이름이 있는 슬롯
name
이라는 속성으로 컨텐츠가 렌더링되어야 하는 위치를 결정할 수 있다.
name
속성이 없다면 기본적으로 default
란 이름을 갖는다.
<template>
<div class="container">
<header>
<slot name="header"></slot>
</header>
<main>
<slot></slot>
</main>
<footer>
<slot name="footer"></slot>
</footer>
</div>
</template>
- 이름이 있는 슬롯을 전달하려면 부모 컴포넌트에서
<template>
엘리먼트와 함께 v-slot
디렉티브를 사용하고 슬롯명을 v-slot
인자로 전달해야 한다.
v-slot
의 단축 문법은 #
이 있으므로 <template #footer>
처럼 단축하여 사용할 수 있다.
<BaseLayout>
<template v-slot:header>
<h1>Header</h1>
</template>
<template #default>
<p>Main</p>
</template>
<template #footer>
<p>Footer</p>
</template>
</BaseLayout>
- 컴포넌트가 기본 슬롯과 이름이 있는 슬롯을 모두 허용하는 경우, 최상위 비
<template>
노드는 기본 슬롯의 컨텐츠로 처리된다. 따라서 위의 예시는 아래처럼 작성할 수 있다.
<BaseLayout>
<template v-slot:header>
<h1>Header</h1>
</template>
<p>Main</p>
<template #footer>
<p>Footer</p>
</template>
</BaseLayout>
- 최종 렌더링된 HTML 결과는 아래와 같다.
2. 동적인 슬롯 이름
- 동적인 디렉티브 인자는
v-slot
에서도 작동한다.
<BaseLayout>
<template v-slot:[dynamicSlotName]>
...
</template>
<template #[dynamicSlotName]>
...
</template>
</BaseLayout>
3. 범위가 지정된 슬롯
- 슬롯 컨텐츠는 부모 컴포넌트에 정의되어 있으므로 부모 컴포넌트의 데이터 범위에 접근할 수 있다.
<template>
<p>{{ firstName }}</p>
<MyComponent>{{ firstName }}</MyComponent>
</template>
<script>
import MyComponent from './components/MyComponent.vue';
export default {
...
data() {
return {
firstName: 'Dohee'
}
}
}
</script>
- 다음과 같이 상위 컴포넌트에서 선언된 슬롯 컨텐츠에서 자식 컴포넌트(하위) 범위 내에 있는 데이터를 사용할 수 없다.
<template>
<MyComponent>{{ greetingMsg }}</MyComponent>
</template>
<script>
export default {
data() {
return {
greetingMsg: '안녕',
count: 1
}
}
}
</script>
- 아래 코드처럼 작성하면 자식 컴포넌트(하위) 범위 내에 있는 데이터를 상위 컴포넌트에서 선언된 슬롯 컨텐츠에서 사용할 수 있다.
<slot :text="greetingMsg" :count="count" />
- 속성을 부모 컴포넌트에 작성된 슬롯 컨텐츠에 전달
<MyComponent v-slot="slotProps">
- 단일 기본 슬롯을 사용할 때와 달리
v-slot
을 통해 슬롯 props를 받는다.
<p>{{ slotProps.text }} {{ slotProps.count }}</p>
- 슬롯 범위 내에서 슬롯 props를 통해 값을 사용할 수 있다.
<template>
<MyComponent v-slot="slotProps">
<p>{{ slotProps.text }} {{ slotProps.count }}</p>
</MyComponent>
</template>
<template>
<div>
<slot :text="greetingMsg" :count="count" />
<button type="button" @click="count++">Click</button>
</div>
</template>
<script>
export default {
data() {
return {
greetingMsg: '안녕',
count: 1
}
}
}
</script>
v-slot
은 분해 할당하여 사용할 수 있다.
<MyComponent v-slot="{ text, count }">
{{ text }} {{ count }}
</MyComponent>
- 이름이 있고 범위가 지정된 슬롯은 아래와 같이 사용할 수 있다.
<MyComponent>
<template #header="headerProps">
{{ headerProps }}
</template>
<template #default="defaultProps">
{{ defaultProps }}
</template>
<template #footer="footerProps">
{{ footerProps }}
</template>
</MyComponent>
- 명명된 슬롯과 기본 범위 슬롯을 혼합하여 컴포넌트에
v-slot
지시어를 사용하면 컴파일 에러가 발생한다.
- 기본 슬롯의
props
범위에 대한 모호함을 피하기 위한 에러
<template>
<MyComponent v-slot="{ message }">
<p>{{ message }}</p>
<template #footer>
<p>{{ message }}</p>
</template>
</MyComponent>
</template>
- 기본 슬롯에 명시적인
<template>
을 사용하여 v-slot
사용을 피해 다른 슬롯에서 message
prop을 사용할 수 없음을 명확히 알 수 있다.
<template>
<MyComponent>
<template #default="{ message }">
<p>{{ message }}</p>
</template>
<template #footer>
<p>Here's some contact info</p>
</template>
</MyComponent>
</template>