Template Refs
Template Refs ermöglichen direkten Zugriff auf DOM-Elemente oder Kind-Komponenten-Instanzen.
Sie werden verwendet, wenn deklarative Datenbindung nicht ausreicht und direkter DOM-Zugriff nötig ist.
Grundlagen
Abschnitt betitelt „Grundlagen“<script setup>import { ref, onMounted } from 'vue'
// Ref mit gleichem Namen wie im Templateconst inputElement = ref(null)
onMounted(() => { // DOM-Element ist jetzt verfügbar console.log(inputElement.value) // <input> Element inputElement.value.focus()})</script>
<template> <!-- ref-Attribut verknüpft mit der Variable --> <input ref="inputElement" type="text" /></template>Timing: Wann sind Refs verfügbar?
Abschnitt betitelt „Timing: Wann sind Refs verfügbar?“<script setup>import { ref, onMounted, watchEffect } from 'vue'
const inputRef = ref(null)
// Noch nicht verfügbar - vor mountconsole.log(inputRef.value) // null
onMounted(() => { // Jetzt verfügbar - nach mount console.log(inputRef.value) // <input>})
// watchEffect trackt ref automatischwatchEffect(() => { if (inputRef.value) { inputRef.value.focus() }})</script>
<template> <input ref="inputRef" /></template>Refs in v-for
Abschnitt betitelt „Refs in v-for“<script setup>import { ref, onMounted } from 'vue'
const items = ref(['A', 'B', 'C'])const itemRefs = ref([]) // Array für mehrere Refs
onMounted(() => { console.log(itemRefs.value) // [<li>, <li>, <li>] console.log(itemRefs.value.length) // 3})</script>
<template> <ul> <li v-for="item in items" :key="item" ref="itemRefs"> {{ item }} </li> </ul></template>Function Refs
Abschnitt betitelt „Function Refs“Statt eines Strings kann eine Funktion verwendet werden für mehr Kontrolle:
<script setup>import { ref } from 'vue'
const inputs = ref(new Map())
function setInputRef(el, id) { if (el) { inputs.value.set(id, el) } else { inputs.value.delete(id) // Cleanup bei Unmount }}
function focusInput(id) { inputs.value.get(id)?.focus()}</script>
<template> <div v-for="item in items" :key="item.id"> <input :ref="(el) => setInputRef(el, item.id)" /> </div> <button @click="focusInput(2)">Focus #2</button></template>Ref auf Komponenten
Abschnitt betitelt „Ref auf Komponenten“<script setup>import { ref, onMounted } from 'vue'import ChildComponent from './ChildComponent.vue'
const childRef = ref(null)
onMounted(() => { // Zugriff auf Kind-Komponente console.log(childRef.value)
// Methoden aufrufen (wenn exposed) childRef.value.someMethod()
// Properties lesen (wenn exposed) console.log(childRef.value.someData)})</script>
<template> <ChildComponent ref="childRef" /></template>defineExpose: Was ist sichtbar?
Abschnitt betitelt „defineExpose: Was ist sichtbar?“Mit <script setup> sind Komponenten standardmäßig geschlossen. defineExpose macht Eigenschaften verfügbar:
<script setup>import { ref } from 'vue'
const internalData = ref('privat')const publicData = ref('öffentlich')
function internalMethod() { /* ... */ }function publicMethod() { /* ... */ }
// Nur diese sind von außen über ref zugänglichdefineExpose({ publicData, publicMethod})</script><!-- Parent --><script setup>const child = ref(null)// child.value.publicData - funktioniert// child.value.publicMethod() - funktioniert// child.value.internalData - undefined</script>Anwendungsfall: Focus Management
Abschnitt betitelt „Anwendungsfall: Focus Management“<script setup>import { ref, nextTick } from 'vue'
const isEditing = ref(false)const inputRef = ref(null)
async function startEdit() { isEditing.value = true
// Warten bis DOM aktualisiert ist await nextTick()
// Dann fokussieren inputRef.value?.focus() inputRef.value?.select()}</script>
<template> <span v-if="!isEditing" @click="startEdit">Klick zum Bearbeiten</span> <input v-else ref="inputRef" @blur="isEditing = false" /></template>Anwendungsfall: Externe Libraries
Abschnitt betitelt „Anwendungsfall: Externe Libraries“<script setup>import { ref, onMounted, onUnmounted } from 'vue'import Chart from 'chart.js/auto'
const canvasRef = ref(null)let chartInstance = null
onMounted(() => { chartInstance = new Chart(canvasRef.value, { type: 'bar', data: { labels: ['Jan', 'Feb', 'Mar'], datasets: [{ data: [10, 20, 30] }] } })})
onUnmounted(() => { chartInstance?.destroy()})</script>
<template> <canvas ref="canvasRef"></canvas></template>Anwendungsfall: Scroll-Kontrolle
Abschnitt betitelt „Anwendungsfall: Scroll-Kontrolle“<script setup>import { ref, nextTick } from 'vue'
const listRef = ref(null)const items = ref([/* ... */])
function scrollToTop() { listRef.value?.scrollTo({ top: 0, behavior: 'smooth' })}
function scrollToBottom() { const el = listRef.value el?.scrollTo({ top: el.scrollHeight, behavior: 'smooth' })}
function addItem() { items.value.push(newItem) // Nach DOM-Update zum neuen Item scrollen nextTick(() => scrollToBottom())}</script>
<template> <div ref="listRef" class="overflow-auto h-64"> <div v-for="item in items">{{ item }}</div> </div> <button @click="scrollToTop">Nach oben</button></template>Best Practices
Abschnitt betitelt „Best Practices“- Für DOM-APIs (focus, scroll, measure)
- Für externe Libraries (Charts, Maps)
defineExposefür öffentliche API- Null-Check vor Zugriff
- Cleanup in
onUnmounted
- Für Datenbindung (verwende
v-model) - Für Styling (verwende
:class,:style) - Für Events (verwende
@click) - Zu früh zugreifen (vor mounted)
- Kind-Komponenten manipulieren
Dokumentation
Abschnitt betitelt „Dokumentation“Offizielle Vue Dokumentation:
- Template Refs - Grundlagen
- Refs in v-for
- Component Refs
API Referenz: