WEB/Vue.js

[Vue.js] Slot 알아보기

Raymond 2022. 7. 22. 20:06

Slot


재사용 컴포넌트를 만드는 방법중 하나입니다. bootstrap의 modal기능을 가진 코드를 Slot을 이용하여 사용 방법을 알아보겠습니다.

앞 포스팅에서 나온 재사용컴포넌트는 화면 구성요소를 정의하고 데이터를 부모에서 자식 또는 자식에서 부모로 전달해가면서 데이터를 사용하는 재사용컴포넌트입니다. 하지만 slot은 부모에서 자식컴포넌트의 특정 부분만 HTML요소를 재정의 하여 사용할수 있습니다.

참고
modal기능은 재사용성이 좋고 modal안의 내용만 바뀌면 다양한곳에 사용이 가능하므로 재사용컴포넌트로 만든 것입니다. 즉, 데이터만 주고받는게 아니라 HTML UI자체가 바뀌는 것은 slot으로 만들면 좋습니다.

예제

폴더구조

project
|--src
    |--component
    |   |--fragments
    |		|--SlotModal.vue
    |--views
    |	|--reuse
    |		|--SlotView.vue
    |--main.js

 

작동방식

fragments 폴더 안의 SlotModal.vue(자식)를 재사용컴포넌트로써 사용하기 위해서는 views의 SlotView.vue(부모)에서 다음의 코드를 작성하면 사용을 할 준비가 됩니다.

import SlotModal from '@/components/fragments/SlotModal.vue'
export default {
  components: { SlotModal },
}

 

부트스트랩의 static backdrop 모달을 재사용컴포넌트로 사용을 할 것이므로 버튼기능은 SlotModal.vue(자식)에 필요가 없습니다. 즉, 버튼은 부모컴포넌트에서 정의하고 slot기능으로 modal을 불러오는 방식입니다. 버튼을 보면 data-bs-target과 slot으로 사용할 재사용컴포넌트의 id값이 같아야 함을 볼 수 있습니다. 이를 맞춰주기 위해 SlotView.vue(부모)에서 <slot-modal modalId = "userModal">로 id 값을 SlotModal.vue(자식)에 넘겨 값을 맞추어 주고 props에 받을 data인 modalId를 정의 합니다. 이후 SlotView.vue(부모)에서 변수를 넘겨받을 :id="`${modalId}Label`" , :aria-labelledby="`${modalId}Label`" 그리고 <slot name="title"></slot>, <slot name="body"></slot>, <slot name="footer"></slot>를  SlotModal.vue(자식)에 정의합니다. 이후  SlotView.vue(부모)에서 <slot-modal modalId="userModal"></slot-modal>태그 안쪽에 name으로 값을 지정한 <template v-slot:title></template><template v-slot:body></template>, <template v-slot:footer></template>를 만들어 SlotModal.vue(자식)에 넘겨줄 데이터를 입력합니다.

static backdrop

SlotView.vue(부모 컴포넌트)

<template>
  <div>
    <button
      class="btn btn-primary"
      data-bs-toggle="modal"
      data-bs-target="#userModal"
    >
      Show Modal
    </button>
    <slot-modal modalId="userModal">
      <template v-slot:title>모달창 타이틀</template>
      <template v-slot:body>
        <div class="row gy-2">
          <div class="col-3">
            <label for="" class="form-label">이메일주소</label>
          </div>
          <div class="col-9">
            <input type="email" name="" id="" class="form-control" />
          </div>
          <div class="col-3">
            <label for="" class="form-label">전화번호</label>
          </div>
          <div class="col-9">
            <input type="tel" name="" id="" class="form-control" />
          </div>
          <div class="col-3">
            <label for="" class="form-label">주소</label>
          </div>
          <div class="col-9">
            <input type="text" name="" id="" class="form-control" />
          </div>
        </div>
      </template>
      <template v-slot:footer>
        <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">
          닫기
        </button>
        <button type="button" class="btn btn-primary">저장</button>
      </template>
    </slot-modal>
  </div>
</template>
<script>
import SlotModal from '@/components/fragments/SlotModal.vue'
export default {
  components: { SlotModal },
  data() {
    return {
      sampleData: ''
    }
  },
  setup() {},
  created() {},
  mounted() {},
  unmounted() {},
  methods: {}
}
</script>

 

SlotModal.vue(자식 컴포넌트)

<template>
  <div
    class="modal fade"
    :id="modalId"
    data-bs-backdrop="static"
    data-bs-keyboard="false"
    tabindex="-1"
    :aria-labelledby="`${modalId}Label`"
    aria-hidden="true"
  >
    <div class="modal-dialog">
      <div class="modal-content">
        <div class="modal-header">
          <h5 class="modal-title" :id="`${modalId}Label`">
            <slot name="title"></slot>
          </h5>
          <button
            type="button"
            class="btn-close"
            data-bs-dismiss="modal"
            aria-label="Close"
          ></button>
        </div>
        <div class="modal-body">
          <slot name="body"></slot>
        </div>
        <div class="modal-footer">
          <slot name="footer"></slot>
        </div>
      </div>
    </div>
  </div>
</template>
<script>
export default {
  components: {},
  props: {
    modalId: {
      type: String,
      default: 'myModal'
    }
  },
  data() {
    return {
      sampleData: ''
    }
  },
  setup() {},
  created() {},
  mounted() {},
  unmounted() {},
  methods: {}
}
</script>

Slot을 이용한 Modal