
팝업창과 같이 전체적인 UI는 유사하지만 내용이 다르게 들어가고싶은 경우가 있습니다. 컴포넌트에 slot을 만들고 v-slot 디렉티브를 이용하면 되는데요. 컴포넌트 UI 내에 원하는 부분은 유동적으로 바꿀 수 있습니다.
v-slot 미리보기
v-slot의 두 가지 기능
v-slot
은 두 가지 기능을 통합한 디렉티브입니다.
그러면 이 두 기능이 어떤 것인지 알아야 하겠죠?
Named slot
컴포넌트를 사용할 때 특정 영역은 상위 컴포넌트에서 태그들을 넣을 수 있도록 하는 기능입니다.
slot
slot
이라는 태그를 사용하는데요. 이 부분에 들어갈 태그 내용은 상위 컴포넌트가 정하도록 하겠다는 의미입니다.
<div class="child">
<h2> Child </h2>
<main>
<slot></slot>
</main>
</div>
상위 컴포넌트에서는 태그 사이에 원하는 태그들을 넣어주면 됩니다.
<div class="parent">
<h1> Parent </h1>
<Child>
<h3> main의 제목 </h3>
<p> main의 내용 </p>
</Child>
</div>
그러면 다음과 같이 렌더링 됩니다.
<div class="parent">
<h1> Parent </h1>
<div class="child">
<h2> Child </h2>
<main>
<h3> main의 제목 </h3>
<p> main의 내용 </p>
</main>
</div>
</div>
왜 이렇게 나오는지 이해가 안되실 수도 있을거 같아서 그림으로도 만들어봤습니다.

slot에 대한 이해가 가시나요?
slot 여러 개 사용하기
위의 예시 경우 하나의 slot을 만들었지만 추가로 여러 개 만들고 싶을 수도 있습니다. 그런 경우에는 명칭을 붙여줘서 구분을 해야합니다. 이를 named slot이라 합니다.
<slot name="명칭"></slot>
Child에 header, footer slot을 추가해보겠습니다.
<div class="child">
<header>
<slot name="header"></slot>
</header>
<main>
<slot></slot> <!-- default -->
</main>
<footer>
<slot name="footer"></slot>
</footer>
</div>
slot에 이름을 넣지 않은 경우는 name이 default가 됩니다.
이전에는 단순히 하위 컴포넌트 안에 내용만 넣으면 됐지만 여러 개인 경우 template
태그와 v-slot
을 사용해야합니다.
<template v-slot:명칭></template>
Parent에 적용해보면
<div class="parent">
<Child>
<template v-slot:header>
<h1> header slot 영역 </h1>
</template>
<!-- <template v-slot> 과 동일-->
<template v-slot:default>
<p> default slot 영역 </div>
</template>
<template v-slot:footer>
<p> footer slot 영역 </div>
</template>
</Child>
</div>
v-slot 약식
v-bind(:
)나 v-on(@
)처럼 v-slot도 #
으로 줄여쓸 수 있습니다.
<template #header></template>
v-slot dynamic slot name
v-slot
에 넣을 이름도 동적으로 정하고 싶다면 괄호[]
를 사용하면 됩니다.
<template v-slot:[컴포넌트 변수]></template>
<template #[컴포넌트 변수]></template>
v-slot 넣지 않은 경우 처리
하위 컴포넌트에서 slot
을 만들어놨지만 상위 컴포넌트에서 해당 slot을 무시할 수도 있습니다. 그럴 경우 하위 컴포넌트에서 처리하는 두 가지 방법이 있습니다.
<slot>슬롯을 채우지 않을 경우 이 글이 나타납니다.</slot>
$slots
값을 통해 조건부 렌더링하기 <main v-if="$slots.default">
<slot></slot>
</main>
<footer v-show="$slots.footer">
<slot name="footer"></slot>
</footer>
Scoped slot
상위 컴포넌트에서 하위 컴포넌트의 값을 가져와 렌더링에 사용할 수 있습니다.
scoped slot 문법
하위 컴포넌트에서 name 외 속성으로 상위 컴포넌트에서 값을 보내줄 수 있습니다.
<slot 속성="값"></slot>
<template v-slot="변수">
<div> {{ 변수.값 }} </div>
</template>
scoped slot 예시
<template>
<div class="child">
<slot name="header" message="hello" :user="user"></slot>
</div>
</template>
<script>
export default {
data() {
return {
user: "vuelog"
};
},
}
</script>
하위 컴포넌트에서 header slot에 message
와 user
라는 값을 올려보내고자 합니다.
<template>
<div class="parent">
<template v-slot:header="headerProps">
<div> {{ headerProps.message }} </div>
<div> {{ headerProps.user }} </div>
</template>
</div>
</template>
header slot에서 사용할 값들은 headerProps
에 담아서 message
와 user
값들을 가져와서 사용합니다. (headerProps는 임의로 지은 변수명입니다)
scoped slot 여러 개
named slot 과 마찬가지로 slot이 여러 개인 경우도 동일하게 사용하면 됩니다.
<div class="child">
<header>
<slot name="header" title="Title"></slot>
</header>
<main>
<slot :content="content"></slot>
</main>
<footer>
<slot name="footer" :message="message"></slot>
</footer>
</div>
<div class="parent">
<Child>
<template v-slot:header="headerProps">
<h1> {{ headerProps.title }} </h1>
</template>
<!-- <template v-slot> 과 동일-->
<template v-slot:default="mainProps">
<p> {{ mainProps.content }} </div>
</template>
<template v-slot:footer="footerProps">
<p>{{ footerProps.message }}</div>
</template>
</Child>
</div>
scoped slot destructuring
매번 headerProps
, mainProps
, footerProps
이렇게 매번 변수명을 지어야하는 건 귀찮은 일이죠. ES6 문법인 구조 분해 문법(destructuring)을 사용하면 됩니다.
<template v-slot:default="{ content }"></template>
마무리하며
v-slot
은 named slot, scoped slot 기능이 합쳐진 것입니다.

다양한 예제를 보며 복습해보겠습니다.
<!-- named slot default -->
<template v-slot></template>
<template v-slot:default></template>
<!-- dynamic named slot -->
<template v-slot:[value]></template>
<!-- named slot 약식 -->
<template #header></template>
<!-- scoped slot -->
<template v-slot:footer="footerProps">{{ footerProps.msg }}</template>
<!-- scoped slot destructuring -->
<template v-slot:default="{ msg }">{{ msg }}</template>
<!-- 응용 -->
<template #[name]="{ msg }">{{ msg }}</template>