Appearance
Kapitel 32: Vue Router (Teil 6) - Route-Guards
📙 Lernziel: Route-Guards (Navigationswächter) meistern!
32.1 Was sind Route-Guards?
Route-Guards ermöglichen es, Navigationen zu überwachen oder zu blockieren.
Anwendungsfälle:
- ✅ Authentifizierung prüfen (Login erforderlich)
- ✅ Berechtigungen prüfen (Admin-Bereich)
- ✅ Daten laden vor Route-Eintritt
- ✅ Formular-Änderungen speichern (Unsaved Changes)
Beispiel-Szenario:
/user/profile → Prüfe ob eingeloggt → Erlaube oder Redirect zu /login32.2 beforeEach() - Global Guard
beforeEach() wird bei jeder Navigation ausgeführt.
Syntax:
javascript
router.beforeEach((to, from, next) => {
// Logik
})Beispiel (Authentifizierung):
javascript
// router/index.js
import { createRouter, createWebHistory } from 'vue-router'
import Home from '../views/Home.vue'
import Login from '../views/Login.vue'
import Dashboard from '../views/Dashboard.vue'
const routes = [
{ path: '/', component: Home },
{ path: '/login', component: Login },
{
path: '/dashboard',
component: Dashboard,
meta: { requiresAuth: true } // Meta-Feld
}
]
const router = createRouter({
history: createWebHistory(),
routes
})
// Global Guard (beforeEach)
router.beforeEach((to, from) => {
const isLoggedIn = localStorage.getItem('token') !== null
// Wenn Route Authentifizierung erfordert
if (to.meta.requiresAuth && !isLoggedIn) {
return { path: '/login' } // Redirect zu Login
}
// Wenn eingeloggt und versucht /login zu besuchen
if (to.path === '/login' && isLoggedIn) {
return { path: '/dashboard' } // Redirect zu Dashboard
}
})
export default routerWichtig:
- ✅
to= Ziel-Route - ✅
from= Aktuelle Route - ✅
return { path: '/login' }= Redirect - ✅
return false= Navigation abbrechen
32.3 beforeResolve() - Global Guard
beforeResolve() wird ausgeführt, kurz bevor Navigation bestätigt wird (nach beforeEach()).
Beispiel (Daten laden):
javascript
// router/index.js
router.beforeResolve(async (to, from) => {
// Daten für Route laden
if (to.meta.requiresData) {
try {
const data = await fetchDataForRoute(to)
to.meta.data = data
} catch (error) {
return { path: '/error' }
}
}
})Unterschied beforeEach() vs beforeResolve():
beforeEach(): Vor allen GuardsbeforeResolve(): Nach allen Guards (kurz vor Navigation)
32.4 afterEach() - Global Hook
afterEach() wird ausgeführt, nachdem Navigation abgeschlossen ist (kann Navigation nicht blockieren).
Beispiel (Analytics):
javascript
// router/index.js
router.afterEach((to, from) => {
// Google Analytics (Seitenaufruf tracken)
console.log(`Navigation: ${from.path} → ${to.path}`)
// In echtem Projekt:
// gtag('config', 'GA_MEASUREMENT_ID', {
// page_path: to.path
// })
})Wichtig:
- ❌ Kann Navigation nicht blockieren
- ✅ Gut für Analytics, Logging, etc.
32.5 Route-Guards (Pro Route)
beforeEnter() - Nur für spezifische Route.
Beispiel:
javascript
// router/index.js
const checkAdmin = (to, from) => {
const userRole = localStorage.getItem('role')
if (userRole !== 'admin') {
return { path: '/unauthorized' }
}
}
const routes = [
{
path: '/admin',
component: AdminView,
beforeEnter: checkAdmin // Guard nur für diese Route
},
{
path: '/dashboard',
component: DashboardView,
beforeEnter: (to, from) => {
const isLoggedIn = localStorage.getItem('token') !== null
if (!isLoggedIn) {
return { path: '/login' }
}
}
}
]Vorteil:
- ✅ Guard nur für spezifische Route
- ✅ Bessere Organisation
32.6 In-Komponente Guards
In-Komponente Guards - Innerhalb von Vue-Komponenten.
Verfügbare Guards:
beforeRouteEnter()- Vor Route-Eintritt (Komponente noch nicht erstellt)beforeRouteUpdate()- Wenn Route sich ändert (z.B./user/1→/user/2)beforeRouteLeave()- Vor Verlassen der Route
Beispiel:
vue
<!-- views/EditUser.vue -->
<script setup>
import { ref } from 'vue'
import { onBeforeRouteLeave, onBeforeRouteUpdate } from 'vue-router'
const user = ref({ name: '', email: '' })
const hasUnsavedChanges = ref(false)
// Guard: Vor Verlassen der Route
onBeforeRouteLeave((to, from) => {
if (hasUnsavedChanges.value) {
const answer = window.confirm('Du hast ungespeicherte Änderungen. Wirklich verlassen?')
if (!answer) {
return false // Navigation abbrechen
}
}
})
// Guard: Wenn Route sich ändert (z.B. /user/1 → /user/2)
onBeforeRouteUpdate((to, from) => {
// Daten neu laden
fetchUserData(to.params.id)
})
</script>
<template>
<div>
<h2>Benutzer bearbeiten</h2>
<form @input="hasUnsavedChanges = true">
<label>Name: <input v-model="user.name" /></label><br>
<label>Email: <input v-model="user.email" /></label><br>
<button @click="hasUnsavedChanges = false">Speichern</button>
</form>
</div>
</template>Wichtig:
- ✅
onBeforeRouteLeave()- Gutt für Unsaved Changes Warnung - ✅
onBeforeRouteUpdate()- Gutt für Dynamische Routes
32.7 Übung: Auth Guard implementieren
Aufgabe: Erstelle einen Guard, der prüft ob Benutzer eingeloggt ist.
Lösung:
1. Router konfigurieren (router/index.js):
javascript
import { createRouter, createWebHistory } from 'vue-router'
import Home from '../views/Home.vue'
import Login from '../views/Login.vue'
import Dashboard from '../views/Dashboard.vue'
import Admin from '../views/Admin.vue'
const routes = [
{ path: '/', component: Home },
{ path: '/login', component: Login },
{
path: '/dashboard',
component: Dashboard,
meta: { requiresAuth: true }
},
{
path: '/admin',
component: Admin,
meta: { requiresAuth: true, requiresAdmin: true }
}
]
const router = createRouter({
history: createWebHistory(),
routes
})
// Auth Guard
router.beforeEach((to, from) => {
const isLoggedIn = localStorage.getItem('token') !== null
const userRole = localStorage.getItem('role')
// Prüfe Authentifizierung
if (to.meta.requiresAuth && !isLoggedIn) {
return { path: '/login' }
}
// Prüfe Admin-Berechtigung
if (to.meta.requiresAdmin && userRole !== 'admin') {
return { path: '/dashboard' }
}
// Wenn eingeloggt und versucht /login zu besuchen
if (to.path === '/login' && isLoggedIn) {
return { path: '/dashboard' }
}
})
export default router2. Login-Komponente (views/Login.vue):
vue
<script setup>
import { ref } from 'vue'
import { useRouter } from 'vue-router'
const router = useRouter()
const username = ref('')
const password = ref('')
const login = () => {
// Simuliere Login
if (username.value === 'admin' && password.value === '123') {
localStorage.setItem('token', 'abc123')
localStorage.setItem('role', 'admin')
router.push('/dashboard')
} else if (username.value === 'user' && password.value === '123') {
localStorage.setItem('token', 'xyz789')
localStorage.setItem('role', 'user')
router.push('/dashboard')
} else {
alert('Falsches Passwort!')
}
}
const logout = () => {
localStorage.removeItem('token')
localStorage.removeItem('role')
router.push('/login')
}
</script>
<template>
<div class="login">
<h2>Login</h2>
<div>
<label>Benutzername: <input v-model="username" /></label><br>
<label>Passwort: <input v-model="password" type="password" /></label><br>
<button @click="login">Einloggen</button>
<button @click="logout">Ausloggen</button>
</div>
</div>
</template>
<style scoped>
.login {
max-width: 400px;
margin: 0 auto;
padding: 20px;
}
button {
margin: 10px 5px;
padding: 10px 20px;
background: #42b883;
color: white;
border: none;
border-radius: 5px;
cursor: pointer;
}
</style>3. Dashboard-Komponente (views/Dashboard.vue):
vue
<script setup>
import { useRouter } from 'vue-router'
const router = useRouter()
const logout = () => {
localStorage.removeItem('token')
localStorage.removeItem('role')
router.push('/login')
}
</script>
<template>
<div class="dashboard">
<h2>Dashboard</h2>
<p>Willkommen im Dashboard!</p>
<button @click="logout">Ausloggen</button>
<router-link to="/admin">Zu Admin</router-link>
</div>
</template>4. Admin-Komponente (views/Admin.vue):
vue
<template>
<div class="admin">
<h2>Admin-Bereich</h2>
<p>Nur für Admins!</p>
<router-link to="/dashboard">Zurück zu Dashboard</router-link>
</div>
</template>✅ Zusammenfassung
In diesem Kapitel hast du gelernt:
- ✅ Was Route-Guards sind
- ✅
beforeEach()(Global Guard) - ✅
beforeResolve()(Global Guard) - ✅
afterEach()(Global Hook) - ✅ Route-Guards (Pro Route)
- ✅ In-Komponente Guards
- ✅ Praxis: Auth Guard implementieren
🎯 Nächster Schritt: In Kapitel 33 lernst du Pinia (State Management)!
← Zurück zu Kapitel 31: Redirects & 404Weiter zu Kapitel 33: Pinia Grundlagen →
