FrameWorks/Vue

Vue의 Slot 파헤치기

ABCD 2024. 6. 12.

Slot

  • slot은 컨텐츠 배포 outlet 역할을 하는 커스템 Vue Eelement

사용방법

App.vue: props 버전

<template>
<main>
<BaseButton text="Cancel" />
<BaseButton text="Submit" right-icon="right-arrow" />
</main>
</template>

App.vue: slot 버전

<template>
<main>
<BaseButton>Cancel</BaseButton>
<BaseButton>Submit <span class="icon right-arrow"></span></BaseButton>
</main>
</template>

Slot에 default값 적용

BaseButton.vue

<template>
<button class="button">
<slot>Submit</slot>
</button>
</template>
  • Slot에 값을 제공하면 default 컨텐츠를 override(재정의) 한다.
<!-- 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 Slots

  • Slot이 서로 고유하도록 설정하는 방법
    • Slot에는 사용자 지정 식별자로 지정할 수 있는 named prop이 있다.

image

<template v-slot:header></template>
<!--위 코드는 아래와 같다.-->
<template #header></template>

Scoped Slots

  • 자식 props를 부모에서 사용 하고자 할 때 사용
    • 하위 Component가 상위 Component가 필요로하는 데이터를 제어하고자 할 때 사용
  • slot의 template 블록에 데이터를 노출할 수 있도록 하는 기술
  • Named Slot을 사용할 수도 있다.
  • 숫자는 상관없지만, 문자의 경우 script에서 변수를 선언해서 담아준 후 return시켜 사용해야 한다.

image 1

사용방법1 (& Named Slots)

App.vue

<script>
import MyComponent from './MyComponent.vue'
export default {
components: {
MyComponent
}
}
</script>
<template>
<MyComponent v-slot="test">
{{ test.text }} {{ test.count }} {{test}}
</MyComponent>
</template>
<!--slot에 있는 prop을 직접 명시해서 다음과 같이 사용할 수도 있다.-->
<template>
<MyComponent v-slot="{text, count}">
{{ text }} {{ count }}
</MyComponent>
</template>

MyComponent.vue

<script>
export default {
data() {
return {
greetingMessage: 'hello'
}
}
}
</script>
<template>
<div>
<slot :text="greetingMessage" :count="1"></slot>
</div>
</template>

스크린샷 2023-08-04 오전 8 51 17

사용방법2 (FancyList)

App.vue

<script>
import FancyList from './FancyList.vue'
export default {
components: {
FancyList
}
}
</script>
<template>
<FancyList api-url="url" :per-page="10">
<template #item="{ body, username, likes }">
<div class="item">
<p>{{ body }}</p>
<p class="meta">by {{ username }} | {{ likes }} likes</p>
</div>
</template>
</FancyList>
</template>
<style scoped>
.meta {
font-size: 0.8em;
color: #42b883;
}
</style>

FancyList.vue

<script>
export default {
props: ['api-url', 'per-page'],
data() {
return {
items: []
}
},
mounted() {
// mock remote data fetching
setTimeout(() => {
this.items = [
{ body: 'Scoped Slots Guide', username: 'Evan You', likes: 20 },
{ body: 'Vue Tutorial', username: 'Natalia Tepluhina', likes: 10 }
]
}, 1000)
}
}
</script>
<template>
<ul>
<li v-if="!items.length">
Loading...
</li>
<li v-for="item in items">
<slot name="item" v-bind="item"/>
</li>
</ul>
</template>
<style scoped>
ul {
list-style-type: none;
padding: 5px;
background: linear-gradient(315deg, #42d392 25%, #647eff);
}
li {
padding: 5px 20px;
margin: 10px;
background: #fff;
}
</style>

스크린샷 2023-08-04 오전 8 51 38

사용방법3 (Renderless Components)

App.vue

<script>
import MouseTracker from './MouseTracker.vue'
export default {
components: {
MouseTracker
}
}
</script>
<template>
<MouseTracker v-slot="{ x, y }">
Mouse is at: {{ x }}, {{ y }}
</MouseTracker>
</template>

MouseTracker.vue

<script>
export default {
data() {
return {
x: 0,
y: 0
}
},
methods: {
update(e) {
this.x = e.pageX
this.y = e.pageY
}
},
mounted() {
window.addEventListener('mousemove', this.update)
},
unmounted() {
window.removeEventListener('mousemove', this.update)
}
}
</script>
<template>
<slot :x="x" :y="y"/>
</template>
728x90
반응형

'FrameWorks > Vue' 카테고리의 다른 글

VueRouter의 Router Instance 파헤치기  (0) 2024.06.21
Vue의 ObjectBinding  (0) 2024.06.12
Vue의 Props 파헤치기  (0) 2024.06.12
Vue의 watchEffect 와 watch 파헤치기  (0) 2024.06.12
Vue의 ModelValue 파헤치기  (0) 2024.06.12

댓글