Zum Inhalt springen

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.

<script setup>
import { ref, onMounted } from 'vue'
// Ref mit gleichem Namen wie im Template
const 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>
<script setup>
import { ref, onMounted, watchEffect } from 'vue'
const inputRef = ref(null)
// Noch nicht verfügbar - vor mount
console.log(inputRef.value) // null
onMounted(() => {
// Jetzt verfügbar - nach mount
console.log(inputRef.value) // <input>
})
// watchEffect trackt ref automatisch
watchEffect(() => {
if (inputRef.value) {
inputRef.value.focus()
}
})
</script>
<template>
<input ref="inputRef" />
</template>
<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>

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>
<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>

Mit <script setup> sind Komponenten standardmäßig geschlossen. defineExpose macht Eigenschaften verfügbar:

ChildComponent.vue
<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änglich
defineExpose({
publicData,
publicMethod
})
</script>
<!-- Parent -->
<script setup>
const child = ref(null)
// child.value.publicData - funktioniert
// child.value.publicMethod() - funktioniert
// child.value.internalData - undefined
</script>
<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>
<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>
<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>
  • Für DOM-APIs (focus, scroll, measure)
  • Für externe Libraries (Charts, Maps)
  • defineExpose fü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

Offizielle Vue Dokumentation:

API Referenz: