Teraz gdy znasz wszystkie narzędzia magazynu modułów NOVA LAB, zobaczmy jak je łączyć w zaawansowane wzorce - jak kompletny system logistyczny stacji.
Renderless component to komponent który nie ma własnego template - dostarcza tylko logikę przez scoped slot. Rodzic ma pełną kontrolę nad renderowaniem.
1<!-- MissionTimer.vue (renderless) -->
2<script setup>
3import { ref, onMounted, onUnmounted } from 'vue'
4
5const count = ref(0)
6const isRunning = ref(false)
7let interval = null
8
9const start = () => {
10 if (!isRunning.value) {
11 isRunning.value = true
12 interval = setInterval(() => count.value++, 1000)
13 }
14}
15
16const stop = () => {
17 isRunning.value = false
18 clearInterval(interval)
19}
20
21const reset = () => {
22 count.value = 0
23 stop()
24}
25
26onUnmounted(() => clearInterval(interval))
27</script>
28
29<template>
30 <slot
31 :count="count"
32 :isRunning="isRunning"
33 :start="start"
34 :stop="stop"
35 :reset="reset"
36 />
37</template>
38
39<!-- Użycie z dowolnym UI -->
40<MissionTimer v-slot="{ count, isRunning, start, stop, reset }">
41 <div class="timer">
42 <h2>{{ count }}s</h2>
43 <button v-if="!isRunning" @click="start">Start</button>
44 <button v-else @click="stop">Pause</button>
45 <button @click="reset">Reset</button>
46 </div>
47</MissionTimer>Nazwy slotów mogą być dynamiczne:
1<script setup>
2import { ref } from 'vue'
3const activeSection = ref('header')
4</script>
5
6<template>
7 <StationPanel>
8 <template v-slot:[activeSection]>
9 <p>Dynamic content for {{ activeSection }}</p>
10 </template>
11 </StationPanel>
12</template>Sprawdzanie jakie sloty zostały przekazane:
1<script setup>
2import { useSlots } from 'vue'
3
4const slots = useSlots()
5
6// Sprawdź czy slot istnieje
7const hasHeader = !!slots.header
8const hasFooter = !!slots.footer
9</script>
10
11<template>
12 <div class="panel">
13 <header v-if="slots.header">
14 <slot name="header" />
15 </header>
16 <main>
17 <slot />
18 </main>
19 <footer v-if="slots.footer">
20 <slot name="footer" />
21 </footer>
22 </div>
23</template>Komponent pośredni może przekazywać sloty dalej w dół:
1<!-- Wrapper.vue -->
2<template>
3 <InnerComponent>
4 <template v-for="(_, name) in $slots" #[name]="slotProps">
5 <slot :name="name" v-bind="slotProps || {}" />
6 </template>
7 </InnerComponent>
8</template>| Wzorzec | Kiedy użyć | |---------|-----------| | Props | Proste dane (string, number, boolean) | | Default slot | Wstrzyknięcie dowolnego HTML | | Named slots | Wiele sekcji do wypełnienia | | Scoped slots | Rendering zależny od danych dziecka | | Renderless | Tylko logika, pełna kontrola UI | | Dynamic components | Przełączanie między komponentami | | Teleport | Renderowanie poza hierarchią DOM | | Async + Suspense | Lazy loading ciężkich komponentów |