採点されません。匿名です。 間違えることは学習の一部です。読むだけでもかまいません。

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問の回答を。