Vue.js ルーティング演習問題

2025-07-31

基本概念まとめ

1. ルーティングの基本設定

  • Vue Routerのインストール: npm install vue-router
  • ルート定義: path, component, name, children などのプロパティ
  • ルーターインスタンスの作成: createRouter()
  • アプリケーションへの統合: app.use(router)

2. ナビゲーションガード

  • グローバルガード: router.beforeEach
  • ルート単位ガード: beforeEnter
  • コンポーネント内ガード: beforeRouteEnter, beforeRouteUpdate, beforeRouteLeave
  • 認証フロー: ログイン状態チェック→リダイレクト

3. 動的ルーティング

  • 動的セグメント: path: '/user/:id'
  • パラメータ取得: $route.params.id または Composition APIの useRoute()
  • 404ルート: ワイルドカードルート path: '/:pathMatch(.*)*'

演習問題(全24問)

初級問題(6問)

基本ルーティング

  1. Vue Routerの基本的な設定(Home, Aboutの2ルート)
  2. ナビゲーションリンク(router-link)の作成
  3. プログラムによるナビゲーション(router.push)

ナビゲーションガード基礎

  1. グローバルbeforeEachガードでコンソールログ出力
  2. ルート固有のbeforeEnterガード実装

動的ルーティング基礎

  1. ユーザーIDをパラメータとして受け取る動的ルート

中級問題(12問)

ルーティング応用

  1. ネストされたルートの設定
  2. 名前付きルートの使用
  3. 名前付きビューの実装
  4. ルートごとのスクロール動作設定

ナビゲーションガード応用

  1. 認証ガードによるルート保護
  2. ログインページへのリダイレクト
  3. ルートメタフィールドを使用した権限制御
  4. コンポーネント内ガードでの離脱確認

動的ルーティング応用

  1. 複数の動的セグメントを持つルート
  2. 正規表現による動的セグメントの制約
  3. 動的ルートの遅延読み込み
  4. 404ページの実装

上級問題(6問)

  1. ルートベースのトランジションアニメーション
  2. パーミッションシステムの実装
  3. タブナビゲーションとの統合
  4. ルート履歴の管理と分析
  5. サーバーサイドレンダリング対応ルーティング
  6. マイクロフロントエンド環境でのルーティング統合

解答例

初級問題解答(1-6問)

解答1: 基本ルーティング設定

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
  }
]

const router = createRouter({
  history: createWebHistory(process.env.BASE_URL),
  routes
})

export default router

解答2: ナビゲーションリンク

<template>
  <nav>
    <router-link to="/">Home</router-link> |
    <router-link to="/about">About</router-link>
  </nav>
  <router-view/>
</template>

解答3: プログラム的ナビゲーション

methods: {
  goToAbout() {
    this.$router.push('/about')
    // または
    this.$router.push({ name: 'About' })
  }
}

解答4: グローバルガード

router.beforeEach((to, from, next) => {
  console.log(`Navigation to: ${to.path}`)
  next() // 必ずnext()を呼び出す
})

解答5: ルート固有ガード

{
  path: '/dashboard',
  component: Dashboard,
  beforeEnter: (to, from, next) => {
    if (!localStorage.getItem('authToken')) {
      next('/login')
    } else {
      next()
    }
  }
}

解答6: 動的ルーティング

{
  path: '/user/:userId',
  name: 'UserProfile',
  component: UserProfile
}

// コンポーネント内でアクセス
this.$route.params.userId
// Composition APIでは
import { useRoute } from 'vue-router'
const route = useRoute()
const userId = route.params.userId

中級問題解答(7-18問)

解答7: ネストされたルート

{
  path: '/dashboard',
  component: DashboardLayout,
  children: [
    {
      path: '',
      component: DashboardHome
    },
    {
      path: 'settings',
      component: DashboardSettings
    }
  ]
}

解答8: 名前付きルート

<router-link :to="{ name: 'UserProfile', params: { userId: 123 } }">
  プロフィール
</router-link>

<!-- プログラム的ナビゲーション -->
<script>
this.$router.push({
  name: 'UserProfile',
  params: { userId: 123 }
})
</script>

解答9: 名前付きビュー

{
  path: '/multi-view',
  components: {
    default: MainContent,
    sidebar: Sidebar,
    header: AppHeader
  }
}

<router-view name="header"/>
<router-view name="sidebar"/>
<router-view/>

解答10: スクロール動作

const router = createRouter({
  scrollBehavior(to, from, savedPosition) {
    if (savedPosition) {
      return savedPosition
    } else if (to.hash) {
      return { selector: to.hash }
    } else {
      return { top: 0 }
    }
  }
})

解答11: 認証ガード

router.beforeEach((to, from, next) => {
  const isAuthenticated = checkAuth()
  if (to.meta.requiresAuth && !isAuthenticated) {
    next('/login')
  } else {
    next()
  }
})

解答12: ログインリダイレクト

// ログインページ
methods: {
  login() {
    // 認証処理...
    const redirect = this.$route.query.redirect || '/'
    this.$router.push(redirect)
  }
}

解答13: ルートメタフィールド

{
  path: '/admin',
  component: AdminPanel,
  meta: { requiresAdmin: true }
}

// ガード内でチェック
if (to.meta.requiresAdmin && !user.isAdmin) {
  next('/access-denied')
}

解答14: 離脱確認

beforeRouteLeave(to, from, next) {
  if (this.hasUnsavedChanges) {
    const confirm = window.confirm('変更が保存されていません。離れますか?')
    if (confirm) next()
    else next(false)
  } else {
    next()
  }
}

解答15: 複数動的セグメント

{
  path: '/product/:category/:id',
  component: ProductDetail
}

// アクセス例
this.$router.push('/product/electronics/123')

解答16: 正規表現制約

{
  path: '/user/:id(\\d+)', // 数値のみ許可
  component: UserDetail
}

解答17: 遅延読み込み

{
  path: '/admin',
  component: () => import('../views/Admin.vue')
}

解答18: 404ページ

{
  path: '/:pathMatch(.*)*',
  name: 'NotFound',
  component: NotFound
}

上級問題解答(19-24問)

解答19: ルートトランジション

<router-view v-slot="{ Component }">
  <transition name="fade" mode="out-in">
    <component :is="Component" />
  </transition>
</router-view>

<style>
.fade-enter-active, .fade-leave-active {
  transition: opacity 0.3s ease;
}
.fade-enter-from, .fade-leave-to {
  opacity: 0;
}
</style>

解答20: パーミッションシステム

// ルート定義
{
  path: '/admin',
  meta: { permissions: ['ADMIN'] }
}

// ガード
router.beforeEach((to, from, next) => {
  const requiredPermissions = to.meta.permissions
  if (requiredPermissions) {
    const hasPermission = checkUserPermissions(requiredPermissions)
    if (!hasPermission) next('/forbidden')
  }
  next()
})

解答21: タブナビゲーション

<router-link
  v-for="tab in tabs"
  :key="tab.path"
  :to="tab.path"
  active-class="active-tab"
>
  {{ tab.name }}
</router-link>
<router-view />

解答22: ルート履歴管理

const routeHistory = []
router.afterEach((to) => {
  routeHistory.push({
    path: to.path,
    timestamp: new Date()
  })
})

// 分析
function getFrequentRoutes() {
  const counts = {}
  routeHistory.forEach(route => {
    counts[route.path] = (counts[route.path] || 0) + 1
  })
  return Object.entries(counts).sort((a, b) => b[1] - a[1])
}

解答23: SSR対応

// Nuxt.jsのasyncData
export default {
  async asyncData({ params }) {
    const post = await fetchPost(params.id)
    return { post }
  }
}

解答24: マイクロフロントエンド

// メインアプリ
{
  path: '/app1/*',
  component: MicroAppContainer,
  meta: { appName: 'app1' }
}

// コンテナコンポーネント
mounted() {
  loadMicroApp(this.$route.meta.appName)
}

これらの解答例は、Vue Routerの基本から高度なユースケースまでを網羅しています。実際のプロジェクトで遭遇する様々なシナリオに対応できるよう、段階的に学習できる構成になっています。