基本概念まとめ
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問)
基本ルーティング
- Vue Routerの基本的な設定(Home, Aboutの2ルート)
- ナビゲーションリンク(router-link)の作成
- プログラムによるナビゲーション(router.push)
ナビゲーションガード基礎
- グローバルbeforeEachガードでコンソールログ出力
- ルート固有のbeforeEnterガード実装
動的ルーティング基礎
- ユーザーIDをパラメータとして受け取る動的ルート
中級問題(12問)
ルーティング応用
- ネストされたルートの設定
- 名前付きルートの使用
- 名前付きビューの実装
- ルートごとのスクロール動作設定
ナビゲーションガード応用
- 認証ガードによるルート保護
- ログインページへのリダイレクト
- ルートメタフィールドを使用した権限制御
- コンポーネント内ガードでの離脱確認
動的ルーティング応用
- 複数の動的セグメントを持つルート
- 正規表現による動的セグメントの制約
- 動的ルートの遅延読み込み
- 404ページの実装
上級問題(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の基本から高度なユースケースまでを網羅しています。実際のプロジェクトで遭遇する様々なシナリオに対応できるよう、段階的に学習できる構成になっています。