1.ルーターのセットアップ
// router/index.ts
import { createRouter, createWebHistory } from 'vue-router'
const router = createRouter({
history: createWebHistory(),
routes: [
{
path: '/',
name: 'home',
component: () => import('@/pages/Home.vue'),
},
{
path: '/blog',
name: 'blog',
component: () => import('@/pages/Blog.vue'),
children: [
{
path: ':slug',
name: 'blog-detail',
component: () => import('@/pages/BlogDetail.vue'),
props: true,
},
],
},
{
path: '/dashboard',
component: () => import('@/layouts/DashboardLayout.vue'),
meta: { requiresAuth: true },
children: [
{ path: '', name: 'dashboard', component: () => import('@/pages/Dashboard.vue') },
{ path: 'settings', name: 'settings', component: () => import('@/pages/Settings.vue') },
],
},
{
path: '/:pathMatch(.*)*',
name: 'not-found',
component: () => import('@/pages/NotFound.vue'),
},
],
scrollBehavior(to, from, savedPosition) {
if (savedPosition) return savedPosition
if (to.hash) return { el: to.hash, behavior: 'smooth' }
return { top: 0 }
},
})
export default router
2. 動的ルート
<!-- pages/BlogDetail.vue -->
<script setup lang="ts">
import { useRoute, useRouter } from 'vue-router'
const route = useRoute()
const router = useRouter()
// Với props: true
const props = defineProps<{ slug: string }>()
// Hoặc từ route params
const slug = route.params.slug as string
// Query params
const page = route.query.page as string // ?page=2
// Programmatic navigation
function goToPost(id: string) {
router.push({ name: 'blog-detail', params: { slug: id } })
}
function goBack() {
router.back()
}
</script>
3. ナビゲーションガード
// Global guard
router.beforeEach(async (to, from) => {
const authStore = useAuthStore()
if (to.meta.requiresAuth && !authStore.isAuthenticated) {
return { name: 'login', query: { redirect: to.fullPath } }
}
if (to.meta.requiresAdmin && authStore.user?.role !== 'admin') {
return { name: 'forbidden' }
}
})
// Per-route guard
{
path: '/admin',
beforeEnter: (to, from) => {
const auth = useAuthStore()
if (auth.user?.role !== 'admin') return false
},
}
<!-- In-component guard -->
<script setup lang="ts">
import { onBeforeRouteLeave } from 'vue-router'
const hasUnsavedChanges = ref(false)
onBeforeRouteLeave((to, from) => {
if (hasUnsavedChanges.value) {
return window.confirm('Bạn có thay đổi chưa lưu. Rời khỏi trang?')
}
})
</script>
4. ルート遷移
<template>
<RouterView v-slot="{ Component, route }">
<Transition :name="route.meta.transition || 'fade'" mode="out-in">
<component :is="Component" :key="route.path" />
</Transition>
</RouterView>
</template>
<style>
.fade-enter-active, .fade-leave-active {
transition: opacity 0.3s ease;
}
.fade-enter-from, .fade-leave-to {
opacity: 0;
}
.slide-enter-active, .slide-leave-active {
transition: transform 0.3s ease;
}
.slide-enter-from { transform: translateX(100%); }
.slide-leave-to { transform: translateX(-100%); }
</style>
次の記事: Pinia による状態管理 — ストア、ゲッター、アクション、プラグイン。