Vue Router — ナビゲーションガード
テクノロジ系 / L04 routing — ルーティング
Vue Router — ナビゲーションガード
グローバルガード beforeEach
import { router } from "./router.js";
import { useAuthStore } from "./stores/auth.js";
router.beforeEach((to, from, next) => {
const auth = useAuthStore();
if (to.meta.requiresAuth && !auth.user) {
next({ path: "/login", query: { redirect: to.fullPath } });
} else {
next();
}
});すべての遷移前に判定。
next() を呼ばないと遷移が止まる。
meta フィールド
{
path: "/dashboard",
component: Dashboard,
meta: { requiresAuth: true },
}→ ガード側で to.meta.requiresAuth でチェック。
per-route ガード
{
path: "/admin",
component: AdminPage,
beforeEnter: (to, from, next) => {
const auth = useAuthStore();
if (auth.user?.role !== "admin") next("/");
else next();
},
}特定ルートだけのガード。
コンポーネント内ガード
<script setup>
import { onBeforeRouteLeave } from "vue-router";
onBeforeRouteLeave((to, from, next) => {
if (formIsDirty.value) {
if (!confirm("変更が破棄されますがよろしいですか?")) {
next(false);
return;
}
}
next();
});
</script>「入力中に離脱する前に警告」のパターン。
next の使い方
next(); // 続行
next(false); // 中止
next("/login"); // リダイレクト
next({ path: "/login", query: { redirect: to.fullPath } }); // object形式
next(new Error("...")); // エラー複雑なら早期 return 構造で明確に。
グローバル afterEach
router.afterEach((to, from) => {
// 全ページ遷移後
document.title = to.meta.title ?? "My App";
trackPageView(to.fullPath);
});タイトル設定・アナリティクス送信に。
エラー時の onError
router.onError((error) => {
console.error("Router error:", error);
Sentry.captureException(error);
});ルート遷移中の例外をキャッチ。
まとめ
beforeEachで全遷移を判定meta.requiresAuthなどで宣言的に制御beforeEnterで per-route ガードonBeforeRouteLeaveで離脱前確認afterEachでタイトル / 追跡next()の使い方が要点
L04 完。次は L05 状態管理 (Pinia)。
考えてみよう
既定では正解・不正解の判定はしません。自分のペースで「答えを見る」を。採点してほしい場合だけ「採点してほしい」を押してください。
Lv1: 基本 — beforeEach + meta
問題
const routes = [
{ path: "/", component: Home },
{ path: "/login", component: LoginPage },
{ path: "/dashboard", component: Dashboard, meta: { requiresAuth: true } },
];
router.beforeEach((to, from, next) => {
const isLoggedIn = !!localStorage.getItem("token");
if (to.meta.requiresAuth && !isLoggedIn) {
next({ path: "/login", query: { redirect: to.fullPath } });
} else {
next();
}
});未ログイン時に /dashboard → /login にリダイレクトされる。
合格基準
- guard が動く
- ログイン後 /dashboard にアクセス可
Lv2: 応用 — onBeforeRouteLeave で離脱確認
問題
<script setup>
import { onBeforeRouteLeave } from "vue-router";
import { ref } from "vue";
const formDirty = ref(false);
onBeforeRouteLeave((to, from, next) => {
if (formDirty.value) {
if (!confirm("Discard changes?")) {
next(false);
return;
}
}
next();
});
</script>
<template>
<input @input="formDirty = true" />
</template>入力後に別ページへ遷移しようとすると確認ダイアログ。
合格基準
- 入力後の遷移で confirm
- キャンセルで遷移止まる
Lv3: 発展 — afterEach でタイトル更新
問題
const routes = [
{ path: "/", component: Home, meta: { title: "Home" } },
{ path: "/about", component: About, meta: { title: "About Us" } },
];
router.afterEach((to) => {
document.title = (to.meta.title as string) ?? "My App";
});ページ遷移ごとにブラウザタブのタイトルが変わる。
合格基準
- 各ページで title 更新
- meta.title が空ならフォールバック
提出
submission.md に3問の回答を。