Modul 7: Vue Ökosystem

VueUse

200+ Composables für produktive Vue-Entwicklung

Was ist VueUse?

VueUse ist eine Sammlung von über 200 sofort einsetzbaren Composition-API-Utilities (sogenannten Composables) für Vue 3. Statt das Rad jedes Mal neu zu erfinden, greifst du auf getestete, typsichere Funktionen zu — von Browser-APIs über Sensoren bis hin zu State-Helfern.

Die Bibliothek ist tree-shakable: Du importierst nur, was du brauchst, und der Rest wird beim Build entfernt. Jedes Composable ist eine einzelne Funktion, die reaktive Refs zurückgibt — perfekt für die Composition API.

🛤️

Rails-Vergleich: Gems vs. Composables

In Rails installierst du Gems wie devise, pundit oder pagy, um wiederkehrende Aufgaben zu lösen. VueUse ist das Vue-Pendant — eine kuratierte Sammlung kleiner, fokussierter Bausteine. Der Unterschied: Composables sind keine Klassen oder Module, sondern Funktionen, die du direkt im setup() aufrufst und die reaktive Daten zurückgeben.

Installation und Einrichtung

Terminal
# Installation
npm install @vueuse/core

# Optional: Integrations (Firebase, RxJS, etc.)
npm install @vueuse/integrations

Nach der Installation importierst du einzelne Composables direkt — kein Plugin, keine globale Registrierung nötig:

MeineKomponente.vue
<script setup>
import { useMouse, useLocalStorage } from '@vueuse/core'

const { x, y } = useMouse()
const name = useLocalStorage('user-name', 'Gast')
</script>

<template>
  <p>Maus: {{ x }}, {{ y }}</p>
  <input v-model="name" />
</template>

Die 15 nützlichsten Composables

1. useMouse — Mausposition

Liefert die aktuelle Mausposition als reaktive Refs.

MouseTracker.vue
<script setup>
import { useMouse } from '@vueuse/core'

const { x, y, sourceType } = useMouse()
// x, y = reaktive Refs mit Pixelwerten
// sourceType = 'mouse' | 'touch'
</script>

<template>
  <p>Position: {{ x }}, {{ y }} ({{ sourceType }})</p>
</template>

2. useLocalStorage — Persistenter State

Synchronisiert eine Ref automatisch mit localStorage. Änderungen überleben Seiten-Reloads.

setup
import { useLocalStorage } from '@vueuse/core'

// Zweiter Parameter = Standardwert
const theme = useLocalStorage('app-theme', 'light')
const user = useLocalStorage('user-prefs', { lang: 'de', fontSize: 16 })

// Schreiben aktualisiert automatisch localStorage
theme.value = 'dark'
user.value.fontSize = 18
🛤️

Rails-Vergleich

Das entspricht cookies.permanent oder Rails.cache.fetch — nur clientseitig und reaktiv.

3. useDark — Dark Mode

Erkennt und toggelt den Dark Mode mit einem einzigen Aufruf.

setup
import { useDark, useToggle } from '@vueuse/core'

const isDark = useDark()          // reaktive Ref<boolean>
const toggleDark = useToggle(isDark) // Toggle-Funktion

// Setzt automatisch class="dark" auf <html>

4. useClipboard — Zwischenablage

Kopiert Text in die Zwischenablage und zeigt den aktuellen Inhalt an.

CopyButton.vue
<script setup>
import { useClipboard } from '@vueuse/core'

const { text, copy, copied, isSupported } = useClipboard()
</script>

<template>
  <button @click="copy('Hallo Welt!')" :disabled="!isSupported">
    {{ copied ? '✅ Kopiert!' : '📋 Kopieren' }}
  </button>
  <p v-if="text">Zwischenablage: {{ text }}</p>
</template>

5. useWindowSize — Fenstergröße

Reaktive Fensterdimensionen — ideal für responsive Logik im Script.

setup
import { useWindowSize } from '@vueuse/core'

const { width, height } = useWindowSize()
// Reaktiv — aktualisiert sich bei Resize automatisch

const isMobile = computed(() => width.value < 768)

6. useFetch — HTTP-Requests

Einfacher Fetch-Wrapper mit reaktivem Zustand für Daten, Fehler und Ladestatus.

UserList.vue
<script setup>
import { useFetch } from '@vueuse/core'

const { data, error, isFetching } = useFetch('/api/users')
  .get()
  .json()
</script>

<template>
  <p v-if="isFetching">Lade...</p>
  <p v-else-if="error">Fehler: {{ error }}</p>
  <ul v-else>
    <li v-for="user in data" :key="user.id">{{ user.name }}</li>
  </ul>
</template>
💡

Tipp

Für komplexere Server-State-Szenarien (Caching, Mutations, Invalidierung) empfiehlt sich Vue Query — siehe nächste Lektion.

7. useDebounce — Entprellen

Verzögert die Aktualisierung eines Werts, bis keine Änderungen mehr kommen.

setup
import { useDebounce } from '@vueuse/core'

const search = ref('')
const debouncedSearch = useDebounce(search, 500)

// debouncedSearch aktualisiert sich erst 500ms
// nach der letzten Änderung von search
watch(debouncedSearch, (val) => {
  fetchResults(val) // API-Call erst nach Tipp-Pause
})

8. useThrottleFn — Drosseln

Führt eine Funktion höchstens alle n Millisekunden aus.

setup
import { useThrottleFn } from '@vueuse/core'

const savePosition = useThrottleFn((x: number, y: number) => {
  console.log('Position gespeichert:', x, y)
}, 1000)

// Wird höchstens 1× pro Sekunde ausgeführt,
// egal wie oft aufgerufen

9. useIntersectionObserver — Sichtbarkeit

Erkennt, ob ein Element im Viewport sichtbar ist — perfekt für Lazy Loading.

LazyImage.vue
<script setup>
import { useIntersectionObserver } from '@vueuse/core'

const target = ref<HTMLElement | null>(null)
const isVisible = ref(false)

useIntersectionObserver(target, ([{ isIntersecting }]) => {
  isVisible.value = isIntersecting
})
</script>

<template>
  <div ref="target">
    <img v-if="isVisible" src="/grosses-bild.jpg" alt="Lazy" />
    <div v-else class="placeholder">Wird geladen...</div>
  </div>
</template>

10. useEventListener — Event-Handling

Registriert Events, die beim Unmount automatisch entfernt werden — kein manuelles removeEventListener nötig.

setup
import { useEventListener } from '@vueuse/core'

// Wird automatisch beim Unmount entfernt!
useEventListener(window, 'keydown', (e: KeyboardEvent) => {
  if (e.key === 'Escape') closeModal()
})

// Auch auf Elemente anwendbar:
const button = ref<HTMLButtonElement | null>(null)
useEventListener(button, 'click', () => doSomething())

11. useMediaQuery — Media Queries

Reaktive CSS Media Queries im JavaScript.

setup
import { useMediaQuery } from '@vueuse/core'

const isLargeScreen = useMediaQuery('(min-width: 1024px)')
const prefersDark = useMediaQuery('(prefers-color-scheme: dark)')
const isRetina = useMediaQuery('(min-resolution: 2dppx)')

// Reactive — aktualisiert sich bei Änderung

12. onClickOutside — Klick außerhalb

Erkennt Klicks außerhalb eines Elements — ideal für Dropdowns und Modals.

Dropdown.vue
<script setup>
import { onClickOutside } from '@vueuse/core'

const dropdown = ref<HTMLElement | null>(null)
const isOpen = ref(false)

onClickOutside(dropdown, () => {
  isOpen.value = false
})
</script>

<template>
  <div ref="dropdown" class="dropdown">
    <button @click="isOpen = !isOpen">Menü</button>
    <ul v-if="isOpen">
      <li>Option A</li>
      <li>Option B</li>
    </ul>
  </div>
</template>

13. useScroll — Scroll-Position

Verfolgt die Scroll-Position eines Elements oder des Fensters.

setup
import { useScroll } from '@vueuse/core'

// Fenster-Scroll
const { x, y, isScrolling, arrivedState } = useScroll(window)

// arrivedState = { top, bottom, left, right }
const showBackToTop = computed(() => y.value > 500)
const isAtBottom = computed(() => arrivedState.bottom)

14. useColorMode — Farbmodus-Verwaltung

Erweiterte Variante von useDark — unterstützt mehrere Modi (light, dark, sepia, etc.) mit automatischer Persistierung.

setup
import { useColorMode } from '@vueuse/core'

const mode = useColorMode({
  modes: {
    light: 'light',
    dark: 'dark',
    sepia: 'sepia',
  },
})

// mode.value = 'light' | 'dark' | 'sepia'
mode.value = 'sepia' // Wechselt Modus + persistiert

15. useBreakpoints — Responsive Breakpoints

Definiere Breakpoints und reagiere reaktiv auf Größenänderungen.

setup
import { useBreakpoints } from '@vueuse/core'

const breakpoints = useBreakpoints({
  sm: 640,
  md: 768,
  lg: 1024,
  xl: 1280,
})

const isMobile = breakpoints.smaller('md')     // < 768px
const isTablet = breakpoints.between('md', 'lg') // 768–1024px
const isDesktop = breakpoints.greater('lg')     // > 1024px
const current = breakpoints.current()           // ['sm'] | ['md'] | ...

Live-Demo: Mausposition & Fenstergröße

Diese Demo kombiniert useMouse und useWindowSize, um Echtzeit-Informationen anzuzeigen. Bewege die Maus und ändere die Fenstergröße!

VueUse Live-Demo
Interaktiv

🖱️ Mausposition

x: 0 / y: 0

📐 Fenstergröße

0 × 0px

📱 Gerät

Mobil

VueUseDemo.vue
<script setup>
import { useMouse, useWindowSize } from '@vueuse/core'

const { x, y } = useMouse()
const { width, height } = useWindowSize()

const deviceType = computed(() => {
  if (width.value < 640) return 'Mobil'
  if (width.value < 1024) return 'Tablet'
  return 'Desktop'
})
</script>

<template>
  <div class="grid grid-cols-2 gap-4">
    <div class="info-card">
      <p>🖱️ Mausposition</p>
      <p>x: {{ x }} / y: {{ y }}</p>
    </div>
    <div class="info-card">
      <p>📐 Fenstergröße</p>
      <p>{{ width }} × {{ height }}px</p>
    </div>
  </div>
  <p>📱 Gerät: {{ deviceType }}</p>
</template>

Zusammenfassung

💡

Das Wichtigste

  • VueUse bietet 200+ fertige Composables für alltägliche Aufgaben.
  • Alles ist tree-shakable — importiere nur, was du brauchst.
  • Jedes Composable gibt reaktive Refs zurück.
  • Events und Observer werden beim Unmount automatisch aufgeräumt.
  • Besuche vueuse.org für die vollständige Dokumentation.