Vue.js 컴포넌트 재사용하기 - slot 편

들어가며

안녕하세요. 오랜만에 블로그 글을 씁니다. 요즘 통 바빠서 블로그 관리를 못했네요. 안 그래도 얼마 전에 State of JS 2018을 보면서 아직도 전 세계의 많은 개발자들이 Vue.js에 많은 관심을 갖고 있다는 것을 깨달았습니다. 지금도 주변에 꽤 많은 분들이 Vue.js로 새롭게 웹 서비스를 구축하고 계시는 것 같아요.

그래서 오늘은 실제로 서비스를 구현하고 계신 분들이 재미있어 할 만한 Vue.js 글을 적어보려고 합니다. 컴포넌트를 재 사용하는 방법에 대해서 시리즈로 연재해보려고 해요. 첫 번째 시리즈는 컴포넌트의 마크업을 확장하는 방법인 slot입니다.

그럼 재밌게 보시고 재밌게 코딩하시는데 도움 되었으면 좋겠습니다 :)
Happy Coding!

Slot

슬롯(slot)은 컴포넌트의 재사용성을 높여주는 기능입니다. 특정 컴포넌트에 등록된 하위 컴포넌트의 마크업을 확장하거나 재정의할 수 있습니다. 바로 코드로 살펴보겠습니다.

<!-- ButtonTab.vue -->
<template>
  <div class="tab panel">
    <!-- 탭 헤더 -->
    <slot></slot>
    <!-- 탭 본문 -->
    <div class="content">
      Tab Contents
    </div>
  </div>
</template>

위 코드는 ButtonTab 컴포넌트의 코드입니다. 탭을 구현한다고 생각하고 탭 헤더와 본문을 구분하는 태그를 작성하였습니다. 여기서 탭 헤더에 들어갈 구체적인 태그를 정하지 않고 일단 <slot> 태그로 빈 칸을 남겨놉니다. 만약 이 컴포넌트를 등록한 상위 컴포넌트에서 <slot> 태그 영역을 구현하지 않으면 해당 부분은 공백으로 표시됩니다.

<slot> 태그의 위치에 주목하면서 ButtonTab 컴포넌트를 TabContainer 컴포넌트의 하위 컴포넌트로 등록합니다.

<!-- TabContainer.vue -->
<template>
  <button-tab>
    <!-- slot 영역 -->
    <h1>First Header</h1>
  </button-tab>
  <button-tab>
    <!-- slot 영역 -->
    <h1>Second Header</h1>
  </button-tab>
  <button-tab>
    <!-- slot 영역 -->
    <h1>Third Header</h1>
  </button-tab>
</template>

<script>
export default {
  components: {
    ButtonTab
  }
}
</script>

TabContainer 컴포넌트에 ButtonTab 컴포넌트를 등록하고 ButtonTab 컴포넌트를 세 곳에 표시했습니다. 여기서 <button-tab> 컴포넌트 태그의 안에 각기 다른 헤더의 내용을 정의했습니다. 만약 ButtonTab 컴포넌트에 <slot> 태그를 정의하지 않았다면 컴포넌트를 등록하는 시점에 마크업을 재정의할 수는 없었을 것입니다.

이처럼 슬롯을 사용하면 컴포넌트의 특정 마크업 영역을 재정의하여 같은 컴포넌트를 각기 다르게 표현할 수 있습니다.

Named Slot

위에서는 슬롯의 개념을 이해하기 위해 1개의 슬롯만 사용했습니다. 슬롯은 name 속성을 지정하여 여러 개 사용할 수도 있습니다. 좀 전 예제에 네임드 슬롯을 적용해보겠습니다.

<!-- ButtonTab.vue -->
<template>
  <div class="tab panel">
    <!-- 탭 헤더 -->
    <slot name="header"></slot>
    <!-- 탭 본문 -->
    <slot name="content"></slot>
  </div>
</template>
<!-- TabContainer.vue -->
<template>
  <button-tab>
    <!-- slot 영역 -->
    <h1 slot="header">First Header</h1>
    <div slot="content" class="content">Tab Contents #1</div>
  </button-tab>
  <button-tab>
    <!-- slot 영역 -->
    <h1 slot="header">Second Header</h1>
    <div slot="content" class="content">Tab Contents #2</div>
  </button-tab>
  <button-tab>
    <!-- slot 영역 -->
    <h1 slot="header">Third Header</h1>
    <div slot="content" class="content">Tab Contents #3</div>
  </button-tab>
</template>
..

하위 컴포넌트에서 정의한 슬롯 태그 영역에 마크업을 재정의할 때 위와 같이 HTML 표준 태그를 사용하는 방법도 있지만 아래와 같이 <template> 태그를 사용할 수도 있습니다.

<button-tab>
  <!-- slot 영역 -->
  <template slot="header">
    <h1>First Header</h1>
  </template>
  <template slot="content">
    <div class="content">Tab Contents #1</div>
  </template>
</button-tab>

마무리

앞에서 배운 slot을 잘 활용하면 컴포넌트의 재 사용성을 극대화 할 수 있습니다. 다음 글에서는 컴포넌트 간의 결합력을 높이는 방법에 대해서 알아보겠습니다 :)

※ 본 글은 패스트캠퍼스 Vue.js 정복 캠프의 수업 자료 일부를 발췌한 것입니다.