W zaawansowanych systemach stacji NOVA LAB musimy czasem bezpośrednio odwoływać się do elementow DOM lub przekazywać dane między komponentami bez props drilling. TypeScript pomaga nam robić to bezpiecznie.
Template ref pozwala uzyskać referencję do elementu DOM:
1<script setup lang="ts">
2import { ref, onMounted } from 'vue'
3
4// Typ elementu HTML — ref może być null przed montowaniem
5const inputRef = ref<HTMLInputElement | null>(null)
6const canvasRef = ref<HTMLCanvasElement | null>(null)
7
8onMounted(() => {
9 // Po montowaniu ref nie jest już null
10 inputRef.value?.focus()
11
12 const ctx = canvasRef.value?.getContext('2d')
13 if (ctx) {
14 ctx.fillStyle = '#00ff88'
15 ctx.fillRect(0, 0, 100, 100)
16 }
17})
18</script>
19
20<template>
21 <input ref="inputRef" placeholder="Wpisz komendę..." />
22 <canvas ref="canvasRef" width="400" height="300" />
23</template>Typ
HTMLInputElement | null mówi TypeScriptowi, że ref może być null (zanim komponent zostanie zamontowany).Można też uzyskać referencję do komponentu dziecka:
1<script setup lang="ts">
2import { ref } from 'vue'
3import SensorPanel from './SensorPanel.vue'
4
5// InstanceType<typeof Component> daje typ instancji komponentu
6const sensorRef = ref<InstanceType<typeof SensorPanel> | null>(null)
7
8function refreshSensors() {
9 // Dostęp do publicznych metod komponentu
10 sensorRef.value?.refresh()
11}
12</script>
13
14<template>
15 <SensorPanel ref="sensorRef" />
16 <button @click="refreshSensors">Odśwież sensory</button>
17</template>provide/inject pozwala przekazywać dane w dół drzewa komponentów. InjectionKey<T> zapewnia bezpieczeństwo typów:1<!-- types.ts -->
2<script lang="ts">
3import type { InjectionKey, Ref } from 'vue'
4
5export interface StationConfig {
6 name: string
7 maxCrew: number
8 sector: string
9}
10
11// Klucz z typem — zapewnia że provide i inject używają tego samego typu
12export const StationConfigKey: InjectionKey<StationConfig> = Symbol('StationConfig')
13export const ThemeKey: InjectionKey<Ref<'dark' | 'light'>> = Symbol('Theme')
14</script>1<!-- Provider (rodzic) -->
2<script setup lang="ts">
3import { provide, ref } from 'vue'
4import { StationConfigKey, ThemeKey } from './types'
5
6const theme = ref<'dark' | 'light'>('dark')
7
8provide(StationConfigKey, {
9 name: 'NOVA LAB',
10 maxCrew: 100,
11 sector: 'Alpha-7'
12})
13
14provide(ThemeKey, theme)
15</script>1<!-- Consumer (dziecko/wnuk) -->
2<script setup lang="ts">
3import { inject } from 'vue'
4import { StationConfigKey, ThemeKey } from './types'
5
6// TypeScript zna typ! StationConfig | undefined
7const config = inject(StationConfigKey)
8
9// Z wartością domyślną — nie jest undefined
10const theme = inject(ThemeKey, ref('dark'))
11
12// Używamy optional chaining bo config może być undefined
13console.log(config?.name) // 'NOVA LAB'
14console.log(theme.value) // 'dark'
15</script>Aby uniknąć
undefined, można użyć wartości domyślnej:1const config = inject(StationConfigKey, {
2 name: 'Unknown',
3 maxCrew: 0,
4 sector: 'N/A'
5})
6// Teraz config jest zawsze StationConfig (nigdy undefined)Można też użyć funkcji fabrykującej:
1const config = inject(StationConfigKey, () => ({
2 name: 'Default',
3 maxCrew: 50,
4 sector: 'Beta'
5}), true) // trzeci arg = true oznacza że to factory function