props & event 를 사용하여 부모, 자식 간의 정보를 교환할 수 있음.
그런데, 교환하고 싶은 게 속성이 아니라 템플릿 정보라면?
👉 이때 사용하는 게 slot
슬롯(Slot)이란?
부모 컴포넌트 → 자식 컴포넌트: 템플릿 정보를 전달하는 방법
템플릿이 뭔데 ❓
생겨 먹은 모양새.. html 이라고 생각하셔
슬롯을 사용하지 않는 경우
- 자식 컴포넌트: CheckBox1.vue
- 부모 컴포넌트: NoSlotTest.vue
- input 태그를 사용해 체크박스 생성
- `:value=id`:체크박스의 값이 id 프로퍼티로 설정
- `:checked=checked`: 체크박스의 초기 체크 상태가 checked 프로퍼티에 따라 결정
- `@change` 이벤트를 통해 체크 상태가 변경될 때마다 부모 컴포넌트 (여기선 NoSlotTest.vue)로 이벤트 전달
📌 4에서 데이터는 `{id, checked: $event.target.checked}` 형태로 전달
id: 체크박스에 할당된 고유 식별자
checked: 현재 체크 상태
- 체크 박스가 체크된 상태일 때, `v-if="checked === true`텍스트는 파란색 & 밑줄
그렇지 않으면, 회색으로 표시 - label 프로퍼티에 설정된 텍스트가 표시
프로퍼티가 뭔데 ❓
👉 script의 `props:[...]` 안에 있는 부모로부터 받아오는 속성
- `:id`, `:checked`, `:label` 에 해당 item의 값을 매핑하여 자식에게 전달
- 체크 상태가 변경될 때마다 `handleCheckedChanged`메서드 호출
이렇게 CheckBox1.vue에서 템플릿을 정해 버리면, 똑같은 모양으로만 렌더링 될 거임
slot은 같은 내용을 다른 모양으로 렌더링하고 싶을 때 사용!
슬롯의 기본 사용법
위의 예제에서, CheckBox 컴포넌트가 부모로부터 label 값을 포함한 템플릿을 전달 받도록 할 거임
- 자식 컴포넌트: CheckBox2.vue
- 부모 컴포넌트: SlotTest.vue
`CheckBox1.vue`에서 `<span>` 태그가 있던 자리가 slot으로 변경됨.
부모 컴포넌트에서 `<CheckBox2></CheckBox2>` 사이에 span을 작성한 모양새임.
위와 같이 전달되고, `slot` 태그 사이 Item은 부모로부터 전달받은 콘텐츠가 없을 때 보여줄 `fallback UI`
명명된 슬롯 (Named Slot)
여러 개의 슬롯을 지정하여 전달하고 싶을 때 사용하는 방식
말 그대로 slot에 `이름`을 붙여줌
- 자식 컴포넌트: CheckBox3.vue
- 부모 컴포넌트: NamedSlot.vue
- 기존에 label을 출력하는 slot에 `name="label"` 속성을 추가.
- `name="icon"`인 새로운 slot 추가
위의 icon 슬롯과 label 슬롯에 전달될 템플릿들임
template 태그 내에 `v-slot: xxx` 로 어느 슬롯에 렌더링할 템플릿인지 설정
👉 반드시 template 태그를 사용해서 각 슬롯을 명시적으로 지정해야함!
📌 명명된 슬롯은 화면의 레이아웃을 관리할 목적으로 사용됨.
∵ 같은 내용이라도 다르게 보여주고 싶을 수가 있잖아요?
범위 슬롯 (Scoped Slot)
기존에는 부모에 있는 데이터를 활용해서 자식에게 전달했음.
그런데 자식에 있는 데이터를 렌더링하고 싶으면 ???
👉 이때 범위 슬롯 사용, 속성을 전달하듯, 자식에서 부모로 데이터 전달
전달된 데이터는 슬롯 템플릿 <template> 내부 범위 (Scope)에서만 사용하기 때문에 범위 슬롯이라고 부름
부모는 템플릿을 작성하는데, 자식에게서 받아온 데이터를 사용해서 렌더링하는 것.
아래 그림을 통해 범위 스코프의 개념을 이해해보자.
- 부모 컴포넌트 (ScopedSlot)
- `<template v-slot:default="p1">` 구문을 사용해 자식 컴포넌트로부터 데이터를 받아옴
- 여기서 v-slot:default="p1"은 `p1`이라는 이름으로 접근할 수 있음을 의미
- `{p.label}`은 자식 컴포넌트에서 전달 받은 데이터 중 `label` 속성을 출력
- 자식 컴포넌트 (CheckBoxList)
- 부모에게 데이터를 전달하기 위해 <slot> 태그 사용
- <slot :checked="item.checked" :label="item.label"> 은 `item.checked`와 `item.label`을 부모에게 전달
- 이 데이터는 부모에서 정의한 `v-slot` 을 통해 접근 가능
v-slot:default인 이유❓
여러 개의 슬롯이 있을 때 이름이 지정되지 않은 슬롯을 기본 슬롯 이라고 함
이 기본 슬롯은 부모에서 `v-slot:default` 또는 `v-slot`으로 접근 가능