본문 바로가기

VUE

vue.js v-slot 사용 방법

반응형

Vue.js에서는 여러 컴포넌트를 조합해 UI를 만들어낼 수 있는데, 이때 <slot>을 사용하면 다른 컴포넌트에서 그 자리에 콘텐츠를 추가할 수 있습니다. 그리고 v-slot 디렉티브를 사용하면 <slot> 요소를 더욱 강력하게 제어할 수 있습니다.

 

 

v-slot의 예시

 

1. Scoped Slot
v-slot을 사용하여 상위 컴포넌트에서 하위 컴포넌트로 데이터를 전달하는 것 외에도, scoped slot을 사용하여 하위 컴포넌트에서 상위 컴포넌트로 데이터를 전달할 수 있습니다. 예를 들어, 하위 컴포넌트에서 사용자가 입력한 데이터를 상위 컴포넌트로 전달하는 경우 scoped slot을 사용할 수 있습니다.

 

<!-- Parent Component -->
<template>
  <Child>
    <template v-slot:default="slotProps">
      <div>{{ slotProps.data }}</div>
    </template>
  </Child>
</template>

<!-- Child Component -->
<template>
  <div>
    <input v-model="inputData">
    <slot :data="inputData"></slot>
  </div>
</template>

 

위 코드에서, Parent Component는 Child Component를 사용하고 있습니다. Parent Component는 Child Component의 default slot을 사용하여 Child Component에서 전달받은 데이터를 렌더링합니다. Child Component에서는 slot에 data 속성을 전달하고 있으며, Parent Component에서는 slotProps를 사용하여 slot에 전달된 데이터를 받고 있습니다.

 

 

 

2. Dynamic Slot Name
v-slot은 동적으로 슬롯 이름을 지정할 수 있는 기능도 제공합니다. 예를 들어, 아래와 같이 v-bind를 사용하여 슬롯 이름을 동적으로 변경할 수 있습니다.

 

<template>
  <Child>
    <template v-bind:[dynamicSlotName]="slotProps">
      <div>{{ slotProps.data }}</div>
    </template>
  </Child>
</template>

<!-- Child Component -->
<template>
  <div>
    <input v-model="inputData">
    <slot :name="slotName" :data="inputData"></slot>
  </div>
</template>

<script>
export default {
  data() {
    return {
      slotName: 'default'
    }
  },
  computed: {
    dynamicSlotName() {
      return 'slot-' + this.slotName
    }
  }
}
</script>

 

위 코드에서, Parent Component는 Child Component를 사용하고 있습니다. Parent Component는 v-bind를 사용하여 동적으로 슬롯 이름을 지정하고 있습니다. Child Component에서는 slotName이라는 데이터 속성을 사용하여 슬롯 이름을 동적으로 변경하고 있으며, computed 속성을 사용하여 실제로 사용될 슬롯 이름을 계산하고 있습니다.

 

 

 

3. Scoped Slots with v-for
v-for를 사용하여 반복되는 컴포넌트에서 슬롯을 사용할 때, v-slot을 사용하여 슬롯에 전달되는 데이터를 명시적으로 지정할 수 있습니다. 예를 들어, 아래와 같이 v-for를 사용하여 반복되는 컴포넌트에서 슬롯을 사용하는 예시입니다.

 

<!-- Parent Component -->
<template>
  <div>
    <Child v-for="item in items" v-bind:key="item.id">
      <template v-slot:default="slotProps">
        <div>{{ item.name }} - {{ slotProps.index }}</div>
      </template>
    </Child>
  </div>
</template>

<script>
import Child from './Child.vue';

export default {
  components: {
    Child
  },
  data() {
    return {
      items: [
        { id: 1, name: 'Item 1' },
        { id: 2, name: 'Item 2' },
        { id: 3, name: 'Item 3' }
      ]
    }
  }
}
</script>

<!-- Child Component -->
<template>
  <div>
    <slot :index="index"></slot>
  </div>
</template>

<script>
export default {
  props: {
    index: Number
  }
}
</script>

 

위 코드에서, Parent Component는 Child Component를 items 배열의 각 요소마다 생성합니다. Parent Component는 v-for를 사용하여 Child Component를 반복하면서, 각 Child Component에 슬롯을 전달합니다. 슬롯은 default 이름으로 지정되어 있으며, v-slot 디렉티브를 사용하여 슬롯에 전달되는 데이터를 index로 지정하고 있습니다. Child Component에서는 slot에 index 속성을 전달하고 있으며, Parent Component에서는 slotProps를 사용하여 index 속성을 받고 있습니다.

 

 

 

4. Slot-Specific Props
v-slot을 사용하여 슬롯에 전달되는 속성을 명시적으로 지정할 수도 있습니다. 예를 들어, 아래와 같이 slot-scope 속성을 사용하여 슬롯에 전달되는 데이터의 속성 이름을 지정할 수 있습니다.

 

<!-- Parent Component -->
<template>
  <Child>
    <template v-slot:default="slotProps">
      <div>{{ slotProps.item }}</div>
    </template>
  </Child>
</template>

<!-- Child Component -->
<template>
  <div>
    <slot :item="childData"></slot>
  </div>
</template>

<script>
export default {
  data() {
    return {
      childData: 'Child Component Data'
    }
  }
}
</script>

 

위 코드에서, Parent Component는 Child Component를 사용하고 있습니다. Parent Component는 Child Component의 default slot을 사용하여 Child Component에서 전달받은 데이터 중 item 속성을 렌더링하고 있습니다. Child Component에서는 slot에 item 속성을 전달하고 있으며, Parent Component에서는 slotProps를 사용하여 slot에 전달된 데이터 중 item 속성을 받고 있습니다.

 

 


5. Slot-Specific Events
v-slot을 사용하여 슬롯에서 발생하는 이벤트를 처리할 수도 있습니다. 예를 들어, 아래와 같이 v-on을 사용하여 슬롯에서 발생하는 이벤트를 처리할 수 있습니다.

 

<!-- Parent Component -->
<template>
  <Child>
    <template v-slot:default="{ item }" v-on:custom-event="handleCustomEvent">
      <div>{{ item }}</div>
    </template>
  </Child>
</template>

<!-- Child Component -->
<template>
  <div>
    <button v-on:click="emitCustomEvent">Emit Custom Event</button>
    <slot :item="childData"></slot>
  </div>
</template>

<script>
export default {
  data() {
    return {
      childData: 'Child Component Data'
    }
  },
  methods: {
    emitCustomEvent() {
      this.$emit('custom-event')
    }
  }
}
</script>

 

위 코드에서, Parent Component는 Child Component를 사용하고 있습니다. Parent Component는 Child Component의 default slot에서 발생하는 custom-event 이벤트를 처리하는 handleCustomEvent 메서드를 정의하고 있습니다. Child Component에서는 slot에 item 속성을 전달하고 있으며, 버튼을 클릭할 때 emitCustomEvent 메서드를 호출하여 custom-event 이벤트를 발생시키고 있습니다.

 

 

v-slot의 장단점

 

v-slot을 사용하면 컴포넌트 간의 유연한 조합이 가능해집니다. 하나의 컴포넌트에서 다양한 콘텐츠를 전달받아 다양한 UI를 만들어낼 수 있습니다. 또한 slot 요소를 사용하면 슬롯 내부에 기본값을 지정할 수 있기 때문에, 콘텐츠를 전달하지 않았을 때 기본값을 출력하는 등의 로직을 구현할 수 있습니다.

하지만 v-slot을 사용하면 코드가 복잡해질 수 있습니다. 슬롯을 사용하면 컴포넌트의 구조가 더 복잡해지고, 여러 컴포넌트를 조합하다 보면 슬롯이 어떤 컴포넌트에서 어떤 이름으로 사용되는지 헷갈릴 수 있습니다. 또한 슬롯을 사용하면 데이터 흐름이 복잡해지기 때문에 디버깅이 어려워질 수도 있습니다.

따라서 v-slot을 사용할 때는 슬롯의 이름과 사용 방법을 명확히 정의해야 합니다. 슬롯이 어떤 컴포넌트에서 어떤 이름으로 사용되는지 명확히 정의하고, 슬롯을 사용한 컴포넌트들의 구조를 잘 파악해야 합니다.

그러나 v-slot의 장점은 그만큼 많습니다. v-slot은 Vue.js에서 컴포넌트 간의 유연한 조합을 가능케 하며, 컴포넌트의 재사용성을 높여줍니다. 또한 슬롯을 사용하면 데이터 흐름을 단방향으로 유지할 수 있기 때문에, 양방향 데이터 바인딩에서 발생할 수 있는 문제를 방지할 수 있습니다.

총 결론은, v-slot은 Vue.js에서 매우 강력한 기능 중 하나입니다. 그러나 사용 방법을 제대로 이해하지 않으면 코드를 복잡하게 만들 수 있습니다. 따라서 v-slot을 사용할 때는 슬롯의 이름과 사용 방법을 명확히 정의하고, 슬롯을 사용한 컴포넌트들의 구조를 잘 파악해야 합니다.

반응형