반응형
Vue3에서 slot을 사용하여 유연한 구조, 유연한 합성이 가능한 컴포넌트를 개발하는 방법을 알아봅니다.
이전 시리즈
2022.12.21 - [Vue.js] - Vue3 컴포넌트 디자인 패턴 소개
2022.12.22 - [분류 전체보기] - Vue3 컴포넌트 디자인 패턴 : Slots
Props 중심 컴포넌트의 문제점
props는 설정덩어리다.
- props가 구조를 바꾸고
- props 정의 순서와 사용 순서가 다르고
- props이 거대해 진다면
컴포넌트의 이해와 확장이 어려워진다.
slot이 무엇인가?
슬롯은 콘텐츠 배포 outlet 역할을 하는 커스텀 Vue 엘리먼트다.
HTML 엘리먼트(예: div, span, p 등)로 작업할 때 우리는 자식으로 모든 종류의 입력을 허용한다.
<!-- Just passing a string -->
<div>
This is just normal text
</div>
<!-- Composing text with other HTML elements -->
<div>
This is text with <strong>other HTML elements</strong>.
</div>
즉, 텍스트를 전달하든 다른 엘리먼트를 추가하든 관계없이
컴포넌트는 화면에서 예상대로 렌더링된다.
Vue 컴포넌트의 슬롯을 사용하면 비슷한 효과를 얻을 수 있다.
슬롯을 사용하는 방법
슬롯을 사용하는 것은 다른 HTML 요소만큼 쉽다.
추가 설정은 필요없다.
컴포넌트의 템플릿에 슬롯 요소를 추가하기만 하면 된다.
📄App.vue : props 버전
<template>
<main>
<BaseButton text="Cancel" />
<BaseButton text="Submit" right-icon="right-arrow" />
</main>
</template>
📄App.vue : 슬롯 버전
<template>
<main>
<BaseButton>Cancel</BaseButton>
<BaseButton>Submit <span class="icon right-arrow"></span></BaseButton>
</main>
</template>
슬롯에 디폴트 컨텐츠 적용하기
그냥 슬롯을 채워두기만 하면 된다.
📄BaseButton.vue
<template>
<button class="button">
<slot>Submit</slot>
</button>
</template>
슬롯에 값을 제공하면 디폴트 컨텐츠를 오버라이드(재정의)한다.
<!-- BaseButton with no custom content -->
<BaseButton></BaseButton>
<!-- Rendered BaseButton with no custom content -->
<button class="button">Submit</button>
<!-- BaseButton with custom content -->
<BaseButton>Cancel</BaseButton>
<!-- Rendered BaseButton with custom content -->
<button class="button">Cancel</button>
여러개의 슬롯 사용하기
이를 위해선 named slot과 template block이 필요하다.
named slot이 뭔가요?
named slot은 슬롯이 서로 고유하도록 설정하는 방법이다.
이를 위해 슬롯에는 사용자 지정 식별자로 지정할 수 있는 name prop이 있다.
📄CustomLayout.vue
<div class="container">
<header>
<slot name="header"></slot>
</header>
<main>
<slot></slot>
</main>
<footer>
<slot name="footer"></slot>
</footer>
</div>
그럼 특정 슬롯에 컴포넌트는 어떻게 전달할까?
template block이 뭔가요?
<template> 블록은 SFC의 HTML을 정의하는 방법과 유사하게
슬롯에 전달해야 하는 HTML의 특정 블록을 정의하는 데 사용할 수도 있다.
이를 위하여 v-slot 디렉티브를 적용해야 한다.
v-slot 디렉티브는 콘텐츠를 표시하길 원하는 슬롯 name 인수를 사용할 수 있다.
v-slot 디렉티브는 탬플릿 요소에서만 사용할 수 있다.
📄App.vue
<template>
<CustomLayout>
<template v-slot:header>
<p>Header content</p>
</template>
<template>
<p>Main body content</p>
</template>
<template v-slot:footer>
<p>Footer content</p>
</template>
</CustomLayout>
</template>
v-bind 및 v-on과 유사하게 v-slot에도 단축 구문이 있다. (#)
이전 예제를 다음과 같이 작성할 수 있다.
하지만 해당 방법은 CSS 셀렉터와 혼동을 줄 수 있고, slot에 익숙하지 않은 개발자들을 당황시킬 수 있으니 추천하지 않는다.
📄App.vue
<template>
<CustomLayout>
<template #header>
<p>Header content</p>
</template>
<template>
<p>Main body content</p>
</template>
<template #footer>
<p>Footer content</p>
</template>
</CustomLayout>
</template>
정리
- 슬롯은 컴포넌트에 다양한 유형의 컨텐츠를 제공할 수 있는 유연성을 허용하는 기술이다
- 슬롯의 단점은 컨텐츠에 대한 제약사항(일관성)을 쉽게 제공할 수 없다는 것이다.
- html 기반의 명세/문서화로 어느정도 극복할 수 있다.
- 굳이 하자면 children을 traverse 하는 걸로 되긴 된다...
- 슬롯 내부 작은 컴포넌트의 제약사항은 해당 컴포넌트에서 제공한다.
반응형
'FrontEnd' 카테고리의 다른 글
Vue3 컴포넌트 디자인 패턴 : Object binding (0) | 2022.12.22 |
---|---|
Vue3 컴포넌트 디자인 패턴 : Scoped Slots (0) | 2022.12.22 |
Vue3 컴포넌트 디자인 패턴 : Props (0) | 2022.12.22 |
Vue3 컴포넌트 디자인 패턴 소개 (0) | 2022.12.21 |
[Vue3] Vue3은 리렌더링을 어떻게 트리거할까? (0) | 2022.12.21 |