Vue Router is de officiële oplossing voor single-page (SPA) routing in Vue 3-apps: het verandert de URL zonder volledige herlaadbeurt, rendert het juiste component en werkt correct met de terug- en vooruitknoppen van de browser. Deze gids behandelt routedefinities, dynamische params, programmatische navigatie en de navigation guards die toegangscontrole aansturen, met echte voorbeelden. Alles hier richt zich op Vue Router 4 (de versie die met Vue 3 wordt gebruikt).
Installatie en een basisroutedefinitie
Installeer het pakket en maak een router-instantie. createRouter krijgt een history-modus en een routes-array:
npm install vue-router@4
// src/router/index.js
import { createRouter, createWebHistory } from 'vue-router'
import Home from '../views/Home.vue'
import About from '../views/About.vue'
const routes = [
{ path: '/', name: 'home', component: Home },
{ path: '/about', name: 'about', component: About },
]
export const router = createRouter({
history: createWebHistory(),
routes,
})
Koppel de router vervolgens aan de app:
// src/main.js
import { createApp } from 'vue'
import App from './App.vue'
import { router } from './router'
createApp(App).use(router).mount('#app')
<router-view> bepaalt waar het overeenkomende component wordt gerenderd, en links maak je met <router-link> zodat er geen volledige paginaherlaadbeurt is:
<router-link to="/">Home</router-link>
<router-link :to="{ name: 'about' }">Over ons</router-link>
<router-view />
Routes een naam geven is een goede gewoonte: zelfs als de URL-structuur verandert, blijven links die met name zijn gebouwd werken.
history-modus: web history of hash?
Er zijn twee gangbare keuzes. createWebHistory() levert nette URL's op (/about) maar vereist dat je server elk onbekend pad doorstuurt naar index.html; anders krijg je een 404 bij het herladen. createWebHashHistory() voegt een # toe aan de URL (/#/about) en heeft geen serverconfiguratie nodig — handig voor statische hosting, maar zwakker qua esthetiek en SEO. De meeste moderne projecten kiezen voor web history en voegen een fallback-regel op de server toe.
Dynamische params
Segmenten in een pad die met : beginnen zijn dynamische params. Bijvoorbeeld een detailpagina:
const routes = [
{ path: '/users/:id', name: 'user', component: UserDetail },
]
In het component lees je de param met useRoute(). Een typisch gebruik met de Composition API ziet er zo uit:
<script setup>
import { useRoute } from 'vue-router'
import { watch, ref } from 'vue'
const route = useRoute()
const user = ref(null)
async function load(id) {
user.value = await fetch(`/api/users/${id}`).then(r => r.json())
}
load(route.params.id)
// Volg param-wijzigingen wanneer hetzelfde component wordt hergebruikt
watch(() => route.params.id, (id) => load(id))
</script>
Er is hier een cruciaal punt: wanneer de gebruiker van /users/1 naar /users/2 gaat, hergebruikt Vue dezelfde component-instantie, dus het component wordt niet opnieuw aangemaakt. Daarom moet je route.params.id met watch volgen om de data opnieuw op te halen. Wil je de param liever als prop ontvangen, zet dan props: true op de route; je component krijgt id dan als gewone prop en wordt makkelijker te testen.
Gebruik :id? voor een optionele param, en het patroon /:pathMatch(.*)* om meerdere segmenten op te vangen; dat laatste wordt doorgaans voor een 404-pagina gebruikt.
Programmatische navigatie en query-params
Om vanuit code te navigeren nadat een formulier is verzonden of een actie is voltooid, gebruik je useRouter():
<script setup>
import { useRouter } from 'vue-router'
const router = useRouter()
function goToUser(id) {
router.push({ name: 'user', params: { id } })
}
function search(term) {
router.push({ path: '/search', query: { q: term } })
}
</script>
Query-params (?q=...) lees je via route.query. Gebruik router.replace() om de huidige stap te wijzigen zonder een nieuwe history-vermelding achter te laten, en router.back() om terug te gaan.
Navigation guards: toegangscontrole
Guards laten je ingrijpen voordat een overgang plaatsvindt om die toe te staan, om te leiden of te annuleren — het kerngereedschap voor authenticatie. De meest gebruikte globale guard is beforeEach:
router.beforeEach((to, from) => {
const isAuth = !!localStorage.getItem('token')
if (to.meta.requiresAuth && !isAuth) {
// Een location-object teruggeven leidt de overgang daarheen om
return { name: 'login', query: { redirect: to.fullPath } }
}
// true of niets teruggeven staat de overgang toe
})
De moderne stijl in Vue Router 4 is om een waarde terug te geven in plaats van next() aan te roepen: false annuleert de overgang, een location-object leidt om, en al het andere (of undefined) staat toe. Welke routes beschermd zijn markeer je met het meta-veld in de routedefinitie:
{
path: '/dashboard',
name: 'dashboard',
component: Dashboard,
meta: { requiresAuth: true },
}
Hoef je maar één route te beschermen, gebruik dan de route-eigen beforeEnter-guard. Binnen een component laat onBeforeRouteLeave je controles uitvoeren zoals "je hebt niet-opgeslagen wijzigingen, weet je zeker dat je wilt vertrekken?"
Lazy loading en geneste routes
In grote apps vertraagt het vooraf laden van elke view de eerste opening. Door het component als een dynamische import() door te geven krijg je code splitting op routeniveau; die chunk wordt pas gedownload wanneer de route wordt bezocht:
const routes = [
{ path: '/about', component: () => import('../views/About.vue') },
]
Voor geneste layouts (bijvoorbeeld tabbladen op een gebruikersprofiel) gebruik je children en plaats je een tweede <router-view> in de template van het bovenliggende component:
{
path: '/users/:id',
component: UserLayout,
children: [
{ path: '', component: UserOverview },
{ path: 'posts', component: UserPosts },
],
}
Veelgestelde vragen
Waarom wordt mijn pagina niet bijgewerkt als de param verandert?
Omdat Vue Router hetzelfde component hergebruikt in plaats van het opnieuw aan te maken. Volg route.params met watch en haal de data opnieuw op, of geef het component een unieke :key om een remount te forceren.
Waarom krijg ik een 404 wanneer ik de pagina herlaad?
In web history-modus kent je server paden als /about niet. Configureer de server om alle niet-overeenkomende verzoeken naar index.html door te sturen (de SPA-fallback); kun je dat niet, gebruik dan hash history.
Moet ik next() of return gebruiken in beforeEach?
In Vue Router 4 wordt een waarde teruggeven aanbevolen; het is schoner en minder foutgevoelig. next() werkt nog steeds, maar meng de twee niet in dezelfde guard, anders kan de overgang twee keer worden verwerkt.
Is de routing in je Vue-project rommelig geworden? Laten we je routestructuur, guards en code splitting samen doornemen en er een solide architectuur van maken. Neem contact op en we bouwen een oplossing die bij je behoeften past.