タイトル: ルーティング設定
SEOタイトル: Vue.js ルーティング (Vue Router) 完全ガイド
| この記事の要点 |
|
Vue Router とは
Vue Router は Vue.js 公式のクライアントサイドルーティングライブラリです。SPA (Single Page Application) において、URL と Vue コンポーネントを対応付け、ページ遷移時にコンポーネントを切り替えます。サーバーへのリクエストは発生せず、ブラウザの History API でアドレスバーを書き換えます。
| Vue バージョン | Vue Router バージョン | 主な API |
|---|---|---|
| Vue 3 | vue-router@4.x | createRouter / createWebHistory |
| Vue 2 | vue-router@3.x | new VueRouter() / mode: 'history' |
インストール
# Vue 3 の場合
npm install vue-router@4
# Vue 2 の場合
npm install vue-router@3
# Vite で新規作成時はオプションで含められる
npm create vue@latest
# → "Add Vue Router for Single Page Application development?" → Yes
基本セットアップ (Vue 3 + Composition API)
// 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 },
// Lazy Loading(コード分割)
{ path: '/contact', component: () => import('@/views/Contact.vue') },
];
const router = createRouter({
history: createWebHistory(import.meta.env.BASE_URL),
routes,
});
export default router;// src/main.js
import { createApp } from 'vue';
import App from './App.vue';
import router from './router';
createApp(App)
.use(router)
.mount('#app');
テンプレートでの利用
<!-- App.vue -->
<template>
<nav>
<router-link to="/">Home</router-link> |
<router-link to="/about">About</router-link> |
<router-link :to="{ name: 'contact' }">Contact</router-link>
</nav>
<!-- ここに各ルートのコンポーネントが表示される -->
<router-view />
</template>
<router-link> は内部的に <a href> を生成しますが、クリック時に History API を使うため、ページリロードは発生しません。アクティブな状態には自動で router-link-active / router-link-exact-active クラスが付きます。
history モードの違い
| モード | URL 例 | サーバ設定 |
|---|---|---|
createWebHistory() | /about | ★必須: 全 URL を index.html にフォールバック |
createWebHashHistory() | /#/about | 不要(# 以降はサーバへ送られない) |
createMemoryHistory() | なし | SSR / テスト用 |
動的セグメント (URL パラメータ)
// router/index.js
const routes = [
{ path: '/user/:id', name: 'user', component: User },
// 複数のパラメータ
{ path: '/post/:category/:slug', component: Post },
// オプショナル + 正規表現
{ path: '/items/:id(\\d+)?', component: Items }, // 数字のみ、省略可
];<!-- User.vue -->
<script setup>
import { useRoute, useRouter } from 'vue-router';
import { watch } from 'vue';
const route = useRoute(); // 現在のルート情報(params, query, path, name)
const router = useRouter(); // ルーター本体(push, replace, back)
console.log(route.params.id); // /user/42 → "42"
console.log(route.query.tab); // /user/42?tab=posts → "posts"
// パラメータ変更を監視(同じコンポーネントの使い回し時に必須)
watch(() => route.params.id, (newId, oldId) => {
console.log(`id changed: ${oldId} → ${newId}`);
// 再フェッチ等
});
function goHome() {
router.push('/'); // パス指定
router.push({ name: 'home' }); // ルート名指定
router.push({ name: 'user', params: { id: 99 } });
router.replace('/about'); // 履歴に残さない
router.back(); // 戻る
}
</script>
<template>
<div>User ID: {{ route.params.id }}</div>
</template>
ネストルート
const routes = [
{
path: '/user/:id',
component: User,
children: [
// /user/:id/profile
{ path: 'profile', component: UserProfile },
// /user/:id/posts
{ path: 'posts', component: UserPosts },
// /user/:id(デフォルト子ルート)
{ path: '', component: UserHome },
],
},
];
親コンポーネント側でも <router-view /> を置くと、その位置に子ルートのコンポーネントが描画されます。
ナビゲーションガード
ルート遷移の前後にフックを差し込み、認証チェックやリダイレクトを実装できます。
// グローバルガード
router.beforeEach((to, from, next) => {
if (to.meta.requiresAuth && !isLoggedIn()) {
next({ name: 'login', query: { redirect: to.fullPath } });
} else {
next();
}
});
// 解決後(次画面のコンポーネントロード後)
router.beforeResolve(async (to) => {
if (to.meta.fetchOnEnter) {
await loadData(to);
}
});
router.afterEach((to, from) => {
// 画面遷移後のアナリティクス送信など
gtag('event', 'page_view', { page_path: to.fullPath });
});
// ルート別ガード
const routes = [
{
path: '/admin',
component: Admin,
meta: { requiresAuth: true },
beforeEnter: (to, from) => { /* ... */ },
},
];
Lazy Loading (コード分割)
初期バンドルサイズを抑えるには、各ルートのコンポーネントを動的 import します:
const routes = [
// ❌ 同期 import: 初期バンドルに全部入る
{ path: '/heavy', component: HeavyView },
// ✅ 動的 import: 訪問時に別チャンクをロード
{ path: '/heavy', component: () => import('@/views/HeavyView.vue') },
// チャンク名を指定
{
path: '/dashboard',
component: () => import(/* webpackChunkName: "dashboard" */ '@/views/Dashboard.vue'),
},
];
Vue 2 (vue-router 3.x) との違い
| 項目 | Vue 2 / vue-router 3 | Vue 3 / vue-router 4 |
|---|---|---|
| 作成 | new VueRouter({ routes }) | createRouter({ routes, history }) |
| history | mode: 'history' | history: createWebHistory() |
| 登録 | new Vue({ router }) | app.use(router) |
| 取得 (Composition) | this.$route / this.$router | useRoute() / useRouter() |
| キャッチオール | path: '*' | path: '/:pathMatch(.*)*' |
404 ページの設定
const routes = [
// ... 他のルート
// 最後に: マッチしないものを全部ここへ
{ path: '/:pathMatch(.*)*', name: 'not-found', component: NotFound },
];
FAQ
Q: リロードすると 404 になる
A: createWebHistory モードはサーバ側で「全 URL を index.html にフォールバック」設定が必要です。Nginx なら try_files $uri $uri/ /index.html;、Laravel なら Route::view('/{any}', 'app')->where('any', '.*');。
Q: 同じコンポーネントでパラメータだけ変わったときに再生成されない
A: Vue Router の意図的な最適化です。watch(() => route.params, ...) で監視するか、<router-view :key="$route.fullPath" /> で強制再生成します。
Q: Vue Router で SSR したい
A: Nuxt 3 を使うのが最短です。手動なら createMemoryHistory() + サーバで router.push() → router.isReady() 待ち → レンダリングのフローになります。