[Vue.js] Slot이란? - 컴포넌트 컨텐츠 전달

토끼는 개발개발·2023년 10월 18일
0

Vue.js

목록 보기
16/19
post-thumbnail

📌 Slot

html과 마찬가지로 컴포넌트에 컨텐츠를 전달할 수 있도록 해준다.

한마디로, 특정 내용 뭉텅이를 가져다가 컴포넌트 안에 삽입시키고 싶을 때 쓰는 것이다.

역시 예시로 시작해보자.
FancyButton.vue를 만들었다.

<!--fancyButton.vue-->
<template>
  <button class="fancy-btn">
    <!--이 안에 삽입하고 싶음-->
  </button>
</template>

버튼에서 보여줘야할 텍스트가 화면마다 다르다고 가정해보자.
A화면에서는 '확인'이라는 텍스트를 띄울거고, B화면에서는 '취소'라는 텍스트를 띄우고 싶다.

버튼은 똑같은 버튼이지만, 버튼에 들어갈 텍스트만 달라지는 것이다.
이 경우 사용하는 것이 바로 slot이다.

<!--fancyButton.vue-->
<template>
  <button class="fancy-btn">
    <slot></solt>
  </button>
</template>

부모창에서 fancyButton.vue 버튼 컴포넌트를 불러와서 사용해보자.

<!--theVue.vue-->
<template>
  <fancyButton>확인</fancyButton>
</template>

이제 '확인'이라는 텍스트는 fancyButton.vue의 <slot></slot> 태그를 지정해놓은 곳에 삽입된다.

<!--fancyButton.vue-->
<template>
  <button class="fancy-btn">
    <!--<slot></solt>-->
    확인
  </button>
</template>

위와 같은 결과가 나오는 것이다.

슬롯은 텍스트뿐만아니라 HTML요소, 컴포넌트 등 다양한 모든 컨텐츠가 될 수 있다.




(1) Fallback Content

상위 컴포넌트에서 슬롯 콘텐츠가 제공되지 않을때 슬롯에 대한 폴백(기본 콘텐츠)을 지정할 수 있다.

<!-- FancyButton.vue -->
<template>
  <button class="btn">
    <slot>Default Click!!</slot>
  </button>
</template>

(2) Named Slots

<slot> 요소에 이름을 부여하여 여러개의 <slot>을 정의할 수 있다.

<!-- BaseCard.vue -->
<template>
  <article>
    <div>
      <slot name="header"></slot>
    </div>
    <div>
      <slot></slot>
    </div>
    <div">
      <slot name="footer"></slot>
    </div>
  </article>
</template>
  • <slot>name속성을 부여하여 특정 슬롯 컨텐츠가 렌더링 되어야 할 위치를 설정할 수 있다.
  • name이 없는 <slot>의 이름은 암시적으로 default이다.
<!-- 부모 컴포넌트 사용 예시 -->
<template>
  <BaseCard>
    <template v-slot:header>제목</template>
    <template v-slot:default>안녕하세요</template>
		<template v-slot:footer>푸터</template>
  </BaseCard>
</template>

위 예시처럼 name이 부여된 <slot>에 컨텐츠를 전달하려면 v-slot 디렉티브를 사용하여 전달할 수 있다. 그리고 v-slot:전달인자를 사용하여 지정한 슬롯 컨텐츠에 전달할 수 있다.

v-slot#으로 단축 표현할 수 있다.

<!-- 부모 컴포넌트 사용 예시 -->
<template>
  <BaseCard>
    <template #header>제목</template>
    <template #default>안녕하세요</template>
		<template #footer>푸터</template>
  </BaseCard>
</template>

그리고 default 슬롯은 암시적으로 처리할 수 있다.

<!-- 부모 컴포넌트 사용 예시 -->
<template>
  <BaseCard>
    <template #header>제목</template>
		<!-- 암시적으로 default slot -->
		안녕하세요
		<template #footer>푸터</template>
  </BaseCard>
</template>

(3) Dynamic Slot Named

v-slot 디렉티브 전달인자에 데이터를 바인딩하여 동적으로 변경할 수도 있다.

<BaseCard>
  <template v-slot:[dynamicSlotName]>
    ...
  </template>

  <!-- with shorthand -->
  <template #[dynamicSlotName]>
    ...
  </template>
</BaseCard>

(4) Render Scope

슬롯 콘텐츠는 상위 컴포넌트에 정의되어 있으므로 상위 컴포넌트의 데이터 영역에 접근은 가능하지만 하위 컴포넌트의 영역에는 접근할 수 없다.


(5) Scoped Slots

자식 컴포넌트에서 <slot> 요소를 사용할 때 props를 전달하는 것처럼 속성을 슬롯 컨텐츠에 전달할 수 있다.

(3)Render Scope에서 언급했던 것처럼 슬롯 콘텐츠는 자식 컴포넌트의 데이터에 접근할 수 없다.

다만, 아래와 같이 전달할 수 있다.

<!-- MyComponent.vue -->
<!-- MyComponent.vue -->
<template>
  <div>
    <slot :text="greetingMessage" :count="count"></slot>
  </div>
</template>
<script>
import { ref } from 'vue';

export default {
  setup() {
    const greetingMessage = ref('Hello World!');
    const count = ref(1);
    return {
      greetingMessage,
      count,
    };
  },
};
</script>

default <slot>이 하나 밖에 없는 경우에는 v-slot 디렉티브를 사용하여 props를 전달 받을 수 있다.

<MyComponent v-slot="slotProps">
  {{ slotProps.text }} {{ slotProps.count }}
</MyComponent>

구조분해할당 문법으로 더 편리하게 받을 수 있다.

<MyComponent v-slot="{ text, count }">
  {{ text }} {{ count }}
</MyComponent>

(6) Named Scoped Slots

이름이 부여된 슬롯도 유사하게 작동한다.
v-slot:name="slotProps”

<MyComponent>
  <template #header="headerProps">
    {{ headerProps }}
  </template>

  <template #default="defaultProps">
    {{ defaultProps }}
  </template>

  <template #footer="footerProps">
    {{ footerProps }}
  </template>
</MyComponent>

참고로, 슬롯에 접근하고 싶으면 $slot을 이용하면 된다.




참고문헌

vue3 공식문서 - slot
vue3 완벽마스터 - 짐코딩

profile
하이 이것은 나의 깨지고 부서지는 기록들입니다

0개의 댓글