본문 바로가기

Vue.js

[Udemy Vue 완벽가이드 Section9] 117. 범위가 지정된(scoped) 슬롯

slot은 중요한 기능이다.

slot에 관해 한가지 더 알아보자.

심화기능이지만, 알고 있으면 좋다.

 

CourseGoals.vue라는 새로운 컴포넌트를 만들어보자.

<!--CourseGoals.vue-->
<template>
  <ul>
    <li v-for="goal in goals" :key="goal">{{ goal }}</li>
  </ul>
</template>
<script>
export default {
  data() {
    return {
      goals: ["Finish the course", "Learn Vue"],
    };
  },
};
</script>

 

App.vue로 가서 새로 생성한 CourseGoals.vue 컴포넌트를 불러온다. CourseGoals.vue를 지역 컴포넌트로 등록하면 이제 template에서 사용할 수 있다.

<course-goals></course-goals> 이렇게 입력한다.

이렇게 아래 CourseGoals 컴포넌트가 화면에 출력된다.

 

이 화면이 slot과 어떤 관련이 있을까?

CourseGoals.vue 컴포넌트는 'goals' 데이터를 포함하고, 관련해서 더 많은 로직을 가질 수 있다.

그리고 그 goals를 화면에 렌더링한다.

 

여기서 사용자 정의할 수 있는 요소가 하나 있다. 바로 li 항목의 컨텐츠.

예를 들어 li항목이 text로만 이루어져있다면, h2태그를 가지거나 다른 요소들을 가질 수 있는데 그 부분을 사용자가 원하는대로 지정할 수 있게 만들고싶다.

<li v-for="goal in goals" :key="goal">
 <h2></h2> <!--h2, p부분을 사용자가 원하는대로.-->
 <p></p>
</li>

 

CourseGoals.vue 컴포넌트를 앱의 다른부분에서 사용할 수도 있는데, 요소를 사용할 때 마다 li항목의 컨텐츠가 달라도 된다.

이를 위해 slot을 사용할 수 있다.

여기에 slot을 넣으면, CourseGoals.vue 컴포넌트를 사용하는 컴포넌트에서 HTML 마크업인 컨텐츠가 li 항목에 전달되고, CourseGoals.vue가 사용되는 장소 내에서 정의된다.

<!--CourseGoals.vue 컴포넌트-->
<li v-for="goal in goals" :key="goal">
 <slot></slot>
</li>

 

예를 들어, App.vue에서 course-goal를 사용하고 있으므로 course-goals에 대한 컨텐츠를 전달할 수 있다.

그러면 h2 마크업이 CourseGoals.vue 컴포넌트의 slot 부분으로 전달된다.

<!--App.vue 컴포넌트-->
<course-goals>
 <h2></h2>
</course-goals>

 

이렇게 마크업을 전달할 수 있지만, 문제가 하나 있다.

바로 li항목이 렌더링되는 개별 goal에 접근할 수 없다는 것. slot 부분으로 전달되면 아래와 같이 구현되는데 여기서 h2태그는 goal에 접근할 수가 없다.

<!--CourseGoals.vue 컴포넌트-->
<li v-for="goal in goals" :key="goal">
 <h2></h2>
</li>

goal 변수는 오직 CourseGoals.vue에서 사용할 수 있는데, <slot></slot>에 출력되어야하는 마크업은 App.vue에서 전달된다.

App.vue에서는 CourseGoals.vue에 있는 goal 변수에 접근할 수없다.

 

 

이런 식으로 slot을 구축하는 경우, Vue에서 사용할 수 있는 또다른 기능이 있다.

→ 바로 범위가 지정된(scoped) 슬롯.

이 개념은 'slot을 정의한 컴포넌트 내부(CourseGoals.vue)'에서 'slot에 대한 마크업을 전달한 컴포넌트(App.vue)'에 데이터를 전달할 수 있게 한다.

 

 

이를 위해 data를 가진 컴포넌트에서, 즉 slot을 정의한 컴포넌트(CourseGoals.vue)에서 slot에 prop을 정의한다.

이름은 원하는대로 지으면 된다. 여기서는 'item', 'another-prop'으로 지었다.

<li v-for="goal in goals" :key="goal">
 <slot :item="goal" another-prop="..."></slot>
</li>

반복할 때마다 생성되는 goal을 item에 전달한다.

slot 요소 내에서 설정한 props는 이제 slot에 대한 데이터를 전달하는 곳에서 접근할 수 있게 된다.

이 경우, slot에 마크업을 전달하는 App.vue 이다.

 

 

1/ 데이터를 접근하기 위해서는 slot에 대한 마크업을 template으로 감싼다. slot에 보내고 싶은 마크업을 감싼다. template에 v-slot 또는 축약어(#)를 default 슬롯에 사용할 수 있다.

Named slot에도 같은 개념이 적용된다.

 

2/ 그리고 원하는 이름으로 정의할 수 있다. → 'slotProps'라고 해보자. 원하는 이름을 지으면 된다. 

Vue에서 사용하는 변수의 이름으로, 이 변수의 값은 언제나 '객체'이다.

CourseGoals.vue에서 정의한 모든 props가 병합된 객체. 그래서 데이터를 가진 'another-prop'도 slotProps객체의 프로퍼티가 되고, 'another-prop'이란 key로 접근할 수 있다.

 

slotProps의 값은 { item: 'Finish the course', 'another-prop': '...' } 이렇게다.

 

3/ 이제 slotProps로 무엇을 할 수 있을까?

이 template 안에서 사용할 수 있다. h2 태그 사이에 보간법을 적용하고, slotProps.item으로 접근한다. 

CourseGoals.vue 파일의 slot에서 item prop을 추가했기 때문에 .item으로 접근한다.

item 외에 다른 이름으로 정의했다면, 해당 이름을 slotProps 뒤에 적으면 된다.

<course-goals>
 <template #default="slotProps">
   <h2>{{ slotProps.item }}</h2>
   <p>{{ slotProps['another-prop']}}</p><!--또는 slotProps[anotherProp]도 ok.-->
 </template>
</course-goals>

화면에는 이렇게 구현이 된다.

심화 기능이고 자주 사용되지 않는 기능이지만, 이 기능이 없다면 구축하고자 하는 것을 구축할 수 없는 특정 상황이 있다.

 

 

위 코드를 간단하게 하는 방법이 있는데, default 슬롯과 같이 하나의 슬롯만을 대상으로 할 때, template을 삭제할 수 있다.

불필요한 template wrapper를 삭제하고, #default="slotProps"를 컴포넌트 태그에 직접 넣는다.

여는태그와 닫는 태그 사이에 마크업이 하나의 슬롯에만 해당할 경우에만 적용된다. 이 경우, default 슬롯 하나만 있어서 간단하게 할 수 있다.

<course-goals #default="slotProps">
  <h2>{{ slotProps.item }}</h2>
  <p>{{ slotProps.anotherProp }}</p>
</course-goals>

 

이렇게 슬롯과 범위가 지정된 슬롯에 대해 배웠다.

 

** 출처: 모든 내용은 Udemy Vue-완벽가이드 강의를 기반으로 작성하였습니다.