Slot
html 태그 중에는 컨텐츠가 있어서 다양한 표현을 함.
vue에서 우리 컴포넌트에 컨텐츠를 보내고 싶을 때 쓰는 방법
Slot
사용법
<slot></slot>
위와 같이 사용하면 됨.
<button class="fancy-btn">
<slot></slot>
</button>
위와 같이 slot으로 지정해두면
component를 사용할 때
<FancyButton>Click!</FancyButton>
위와 같이 사용하여 Click! 이란 애를 slot으로 전달해줄 수 있는 것이다.
이런 contents는 그냥 문자열 뿐 아니라
span 태그 같은 태그를 줄 수도 있고
그 안에 style 속성을 줄 수도 있다.
slot을 교체한다고 보면 되는 것임!
기본 콘텐츠를 사용
<slot> 기본콘텐츠 </slot>
위와 같이 하여 default content를 설정할 수 있다.
다중 slot 사용하기 (named slot)
slot:name 으로
해당 slot name 을 따라가 매칭시키게 되어있음
이름을 주지 않으면 default name 임
<template>
<div>
<div class="card">
<div class="card-header"><slot name="header">#header</slot></div>
<div class="card-body">
<slot>#body</slot>
</div>
<div class="card-footer text-muted">
<slot name="footer">#footer</slot>
</div>
</div>
</div>
</template>
<script>
export default {
setup() {
return {};
},
};
</script>
<style lang="scss" scoped></style>
일단 컴포넌트를 생성해서 위와 같이 slot을 넣어주고 name을 준다
name 없으면 default 임
<AppCardVue>
<template v-slot:header> 제목입니다. </template>
<template v-slot:default> 내용입니다. </template>
<template v-slot:footer> 푸터입니다.. </template>
</AppCardVue>
위와 같이 사용하면 해당 name으로 매칭되어 들어가게 됨.
단축표현
# 으로 사용하면 단축표현이 된다고 함.
<AppCardVue>
<template #header> 제목입니다. </template>
<template #default> 내용입니다. </template>
<template #footer> 푸터입니다.. </template>
</AppCardVue>
위와 같이 사용할 수 있는 것임
default 슬롯은 암시적으로 처리할 수 있다 그냥 content 작성하면 암시적으로 default 그냥 들어가짐
<AppCardVue>
<template #header> 제목입니다. </template>
default 설정입니다.
<template #footer> 푸터입니다.. </template>
</AppCardVue>
위와 같이 하면 body로 들어가는 것을 볼 수 있음
또 전달인자를 동적으로 변경할 수 있다.
<template #[slotArgs]> 제목입니다. </template>
위와같이 하여 slotArgs 의 변수를 넣어줄 수 있다.
slotArgs 에 header를 넣거나 footer를 넣거나…
Render scope
slot이 대치된다고 해서
해당 컴포넌트의 변수를 사용할수 있는 것은 아님
오히려 상위 컴포넌트에서 전달해주는 것이기 때문에
상위 컴포넌트의 데이터는 사용할 수 있으나
하위 컴포넌트에서 그려준다고 그 데이터는 사용할수는 없다.
이걸 Render 범위라고 한단다.
그러면 slot 컨텐츠에서 자식 데이터에 접근할수 없을까?
Scoped Slot
<slot :child-message="childMessage" hello-message="안녕하세요">#body</slot>
위와 같이 사용하여 보내면
<template #default="slotProps"> {{ slotProps.childMessage }} </template>
위와 같이 사용하여 객체의 형식으로 받을 수 있는 것이다.
당연히 구조분해 할당으로 받을 수 있다.
<template #default="{ childMessage }"> {{ childMessage }} </template>
위와 같이 사용하는 것도 가능한 것이다
$slots 의 사용법
만약에 card 디자인이 좋은데 body만 사용하고 싶어서 아래와 같이 정했다고 보자
<AppCardVue>게시글입니다.</AppCardVue>
그러면 header 와 footer의 형식은 그대로 남아있을 것임.
그런 경우 해당 컴포넌트에
<div>
<div class="card">
<div v-if="$slots.header" class="card-header">
<slot name="header"></slot>
</div>
<div class="card-body">
<slot
:child-message="childMessage"
hello-message="안녕하세요"
></slot>
</div>
<div v-if="$slots.header" class="card-footer text-muted">
<slot name="footer"></slot>
</div>
</div>
</div>
위와 같이 v-if 에 $slots를 사용하여
header가 정의 되었으면, footer 가 정의 되었으면 렌더링할 수 있도록 만들 수 있다.
그러면 원하는 body 만 남길 수 있는 것이다
setup 에서 slot에 접근하고 싶다면
context.slots 로 접근할 수 있다.
hasFooter 라는 함수를 만들수도 있다.
Component Instance 가 있음