Vue.js Router 速見表:ガード・遅延ロード・トランジションの定石
Vue.js Router を使いこなすには、ナビゲーションガード、遅延ロード、トランジションの 3 つの機能を理解することが重要です。この記事では、実務で即使える定石パターンを速見表とともにご紹介します。
初めて Vue Router を触る方も、すでに使っている方も、この記事を読めば明日から実践できるテクニックが身につくでしょう。
速見表
ナビゲーションガード一覧
| # | ガード種類 | 実行タイミング | 用途 | 定義場所 |
|---|---|---|---|---|
| 1 | beforeEach | 全ルート遷移前 | 認証チェック、ログ記録 | ルーターインスタンス |
| 2 | beforeResolve | ナビゲーション確定直前 | データ取得完了待ち | ルーターインスタンス |
| 3 | afterEach | ナビゲーション完了後 | アナリティクス送信 | ルーターインスタンス |
| 4 | beforeEnter | 特定ルート遷移前 | ルート固有の認証 | ルート定義 |
| 5 | beforeRouteEnter | コンポーネント遷移前 | データプリロード | コンポーネント内 |
| 6 | beforeRouteUpdate | 同一コンポーネント更新時 | パラメータ変更対応 | コンポーネント内 |
| 7 | beforeRouteLeave | コンポーネント離脱前 | 未保存確認 | コンポーネント内 |
遅延ロード実装パターン
| # | パターン | 構文 | メリット | 推奨用途 |
|---|---|---|---|---|
| 1 | 基本的な動的 import | () => import('./Component.vue') | シンプル | 小規模アプリ |
| 2 | webpack チャンク名指定 | () => import(/* webpackChunkName: "group" */ './Component.vue') | グループ化可能 | 中〜大規模アプリ |
| 3 | Prefetch 指定 | () => import(/* webpackPrefetch: true */ './Component.vue') | 事前読み込み | 優先度高いページ |
| 4 | Preload 指定 | () => import(/* webpackPreload: true */ './Component.vue') | 並列読み込み | 初期表示に必要 |
トランジション設定一覧
| # | 設定項目 | 値 | 効果 | 使用例 |
|---|---|---|---|---|
| 1 | name | 文字列 | トランジション名 | "fade", "slide" |
| 2 | mode | "out-in" | 退出後に入場 | ページ切り替え |
| 3 | mode | "in-out" | 入場後に退出 | オーバーレイ |
| 4 | カスタムクラス | enter-active-class | 独自アニメーション | Animate.css 使用時 |
| 5 | JavaScript Hook | @before-enter など | 複雑な制御 | GSAP 使用時 |
背景
SPA におけるルーティングの重要性
Vue.js を使った SPA(Single Page Application)開発では、ルーティングがアプリケーションの核となります。
従来のマルチページアプリケーションと異なり、SPA ではページ遷移時にサーバーへのリクエストが発生しません。すべてのページ遷移は JavaScript 側で制御されるため、ユーザー体験が大きく向上するのです。
しかし、この柔軟性は同時に複雑さも生み出します。ページ遷移前の認証チェック、データの事前読み込み、スムーズなページ切り替えアニメーションなど、考慮すべき点が多岐にわたるでしょう。
Vue Router の 3 つの柱
Vue Router は、これらの課題に対して 3 つの強力な機能を提供しています。
ナビゲーションガードは、ページ遷移の各タイミングでフックを実行し、遷移の制御や前処理を可能にします。遅延ロードは、必要なコンポーネントだけを動的に読み込み、初期読み込み時間を短縮するでしょう。トランジションは、ページ切り替え時のアニメーションを簡単に実装できますね。
次の図は、これら 3 つの機能がルーティングのライフサイクルのどこで働くかを示しています。
mermaidflowchart TD
start["ルート遷移開始"] --> guard1["グローバル<br/>beforeEach"]
guard1 --> guard2["ルート固有<br/>beforeEnter"]
guard2 --> guard3["コンポーネント<br/>beforeRouteEnter"]
guard3 --> lazy["遅延ロード<br/>コンポーネント取得"]
lazy --> guard4["グローバル<br/>beforeResolve"]
guard4 --> transition_out["トランジション<br/>退出アニメーション"]
transition_out --> guard5["グローバル<br/>afterEach"]
guard5 --> transition_in["トランジション<br/>入場アニメーション"]
transition_in --> done["ナビゲーション完了"]
この図から、ナビゲーションガードが遷移の各段階で実行され、遅延ロードがコンポーネント取得時に、トランジションが最終段階で動作することがわかります。
課題
アクセス制御の難しさ
SPA では、すべてのルートが最初からブラウザに読み込まれているため、URL を直接入力すればどのページにもアクセスできてしまいます。
認証が必要なページへの不正アクセスを防ぐには、ページ遷移前にユーザーの権限をチェックする仕組みが必要です。各コンポーネントで個別に認証チェックを実装すると、コードの重複が発生し、メンテナンスが困難になるでしょう。
また、権限チェックのタイミングも重要です。コンポーネントがマウントされてからチェックするのでは遅く、一瞬でも未認証ユーザーにコンテンツが表示されてしまう可能性があります。
パフォーマンスのボトルネック
Vue.js アプリケーションが大規模化すると、すべてのコンポーネントを最初に読み込むと初期読み込み時間が長くなってしまいます。
特にダッシュボードや管理画面など、多数の画面を持つアプリケーションでは、ユーザーがアクセスしない画面まで最初に読み込むのは無駄ですよね。バンドルサイズが大きくなると、モバイル環境でのユーザー体験が著しく低下するでしょう。
Webpack などのバンドラーは最適化機能を持っていますが、開発者が適切にコード分割を指示しなければ、その恩恵を受けられません。
ユーザー体験の向上
ページ遷移が瞬時に行われる SPA では、ユーザーが今どのページにいるのか分かりにくくなることがあります。
突然コンテンツが切り替わると、ユーザーは違和感を覚えるかもしれません。適切なトランジションアニメーションを加えることで、ページ遷移を自然に感じさせ、アプリケーション全体の品質を高められます。
しかし、アニメーションの実装は意外と複雑で、CSS アニメーションと JavaScript の制御を適切に組み合わせる必要があるでしょう。
次の図は、これらの課題がどのように関連しているかを示しています。
mermaidflowchart LR
spa["SPA開発"] --> issue1["アクセス制御<br/>の難しさ"]
spa --> issue2["パフォーマンス<br/>ボトルネック"]
spa --> issue3["UX向上<br/>の必要性"]
issue1 --> prob1["不正アクセス<br/>リスク"]
issue1 --> prob2["コード重複"]
issue2 --> prob3["初期読み込み<br/>遅延"]
issue2 --> prob4["バンドル<br/>肥大化"]
issue3 --> prob5["遷移の<br/>違和感"]
issue3 --> prob6["実装の<br/>複雑さ"]
解決策
ナビゲーションガードで安全な遷移制御
ナビゲーションガードは、ルート遷移のライフサイクル各段階でフックを提供し、遷移の制御や前処理を可能にします。
7 種類のガードが用意されており、それぞれ実行タイミングと用途が異なります。グローバルガードはすべての遷移で実行され、ルート固有ガードは特定のルートでのみ、コンポーネント内ガードはコンポーネントレベルで実行されるのです。
この階層的な設計により、認証チェックはグローバルで、特定ページの権限チェックはルート固有で、といった使い分けができるでしょう。
遅延ロードで最適なパフォーマンス
遅延ロード(Lazy Loading)は、ルートコンポーネントを動的にインポートすることで、必要なときだけコードを読み込む技術です。
JavaScript の動的import()構文を使用し、Webpack などのバンドラーが自動的にコード分割を行います。これにより、初期バンドルサイズを大幅に削減し、アプリケーションの起動時間を短縮できますね。
さらに、Webpack のマジックコメントを使えば、関連するコンポーネントをグループ化したり、事前読み込みを指示したりできるでしょう。
トランジションで洗練された UX
Vue Router のトランジション機能は、Vue の<transition>コンポーネントと統合されており、ページ切り替え時のアニメーションを簡単に実装できます。
CSS トランジション、CSS アニメーション、JavaScript フックのすべてをサポートし、フェード、スライド、ズームなど多様なエフェクトを実現可能です。mode属性により、退出と入場のタイミングを制御できますね。
次の図は、3 つの解決策がどのように課題に対応するかを示しています。
mermaidflowchart LR
guard["ナビゲーション<br/>ガード"] --> solve1["認証・権限<br/>チェック"]
guard --> solve2["遷移制御"]
guard --> solve3["データ<br/>プリロード"]
lazy["遅延ロード"] --> solve4["バンドル<br/>分割"]
lazy --> solve5["初期読み込み<br/>高速化"]
lazy --> solve6["メモリ<br/>効率化"]
transition["トランジション"] --> solve7["スムーズな<br/>切り替え"]
transition --> solve8["視覚的<br/>フィードバック"]
transition --> solve9["ブランド<br/>体験向上"]
具体例
ナビゲーションガードの実装
それでは、実際にナビゲーションガードを実装していきましょう。まずはルーターの基本設定から始めます。
ルーター基本設定
ルーターインスタンスを作成し、グローバルガードを設定します。
typescript// router/index.ts
import { createRouter, createWebHistory } from 'vue-router';
import type { RouteRecordRaw } from 'vue-router';
次に、ルート定義を作成します。メタ情報に認証要否を記載することで、ガードで判断できるようにします。
typescript// ルート定義
const routes: RouteRecordRaw[] = [
{
path: '/',
name: 'Home',
component: () => import('../views/Home.vue'),
},
{
path: '/login',
name: 'Login',
component: () => import('../views/Login.vue'),
},
{
path: '/dashboard',
name: 'Dashboard',
component: () => import('../views/Dashboard.vue'),
meta: { requiresAuth: true }, // 認証が必要
},
];
ルーターインスタンスを作成します。
typescript// ルーターインスタンス作成
const router = createRouter({
history: createWebHistory(),
routes,
});
グローバル beforeEach ガード
最も頻繁に使用されるグローバルガードです。すべてのナビゲーション前に実行され、認証チェックに最適でしょう。
typescript// グローバルbeforeEachガード - 認証チェック
router.beforeEach((to, from, next) => {
// 認証が必要なページかチェック
const requiresAuth = to.matched.some(
(record) => record.meta.requiresAuth
);
// ログイン状態を確認(実際はストアやAPIから取得)
const isAuthenticated =
localStorage.getItem('token') !== null;
if (requiresAuth && !isAuthenticated) {
// 未認証の場合、ログインページへリダイレクト
next({
name: 'Login',
query: { redirect: to.fullPath },
});
} else {
// 認証済み、または認証不要の場合は続行
next();
}
});
このコードでは、to.matched.some()で親ルートも含めて認証要否をチェックしています。next()の引数により、遷移の許可、リダイレクト、キャンセルを制御できますね。
グローバル beforeResolve ガード
すべての非同期コンポーネントが解決された後、ナビゲーション確定直前に実行されます。
typescript// グローバルbeforeResolveガード - データ取得完了確認
router.beforeResolve(async (to, from, next) => {
// ページタイトルを設定
if (to.meta.title) {
document.title = `${to.meta.title} | My App`;
}
next();
});
グローバル afterEach ガード
ナビゲーション完了後に実行されます。遷移を中断できないため、アナリティクスやログ記録に使用します。
typescript// グローバルafterEachガード - アナリティクス送信
router.afterEach((to, from) => {
// Google Analyticsへページビュー送信
if (window.gtag) {
window.gtag('config', 'GA_MEASUREMENT_ID', {
page_path: to.fullPath,
});
}
// ページ遷移のログ記録
console.log(
`ページ遷移: ${from.fullPath} -> ${to.fullPath}`
);
});
ルート固有 beforeEnter ガード
特定のルートにのみ適用されるガードです。管理者ページなど、特別な権限チェックが必要な場合に使用します。
typescript// ルート定義にbeforeEnterを追加
const adminRoute: RouteRecordRaw = {
path: '/admin',
name: 'Admin',
component: () => import('../views/Admin.vue'),
beforeEnter: (to, from, next) => {
// 管理者権限をチェック
const userRole = localStorage.getItem('userRole');
if (userRole === 'admin') {
next();
} else {
// 権限がない場合はホームへリダイレクト
next({ name: 'Home' });
alert('管理者権限が必要です');
}
},
};
コンポーネント内ガード
コンポーネント内で定義するガードです。<script setup>ではonBeforeRouteEnterなどのヘルパーを使用します。
typescript// views/Profile.vue
<script setup lang="ts">
import { onBeforeRouteEnter, onBeforeRouteUpdate, onBeforeRouteLeave } from 'vue-router'
import { ref } from 'vue'
const userData = ref(null)
const hasUnsavedChanges = ref(false)
// コンポーネント遷移前 - データプリロード
onBeforeRouteEnter((to, from, next) => {
// この時点ではコンポーネントインスタンスにアクセス不可
fetchUserData(to.params.id).then(() => {
next()
})
})
// 同一コンポーネント内でパラメータ変更時
onBeforeRouteUpdate(async (to, from) => {
// 新しいユーザーIDでデータ再取得
await fetchUserData(to.params.id)
})
// コンポーネント離脱前 - 未保存確認
onBeforeRouteLeave((to, from) => {
if (hasUnsavedChanges.value) {
const answer = window.confirm('変更が保存されていません。本当に離れますか?')
return answer // falseを返すと遷移キャンセル
}
})
async function fetchUserData(id: string) {
// APIからユーザーデータ取得
const response = await fetch(`/api/users/${id}`)
userData.value = await response.json()
}
</script>
このコンポーネント内ガードの使い分けにより、データの事前読み込みや未保存変更の確認を適切なタイミングで実行できます。
次の図は、ナビゲーションガードの実行順序を示しています。
mermaidsequenceDiagram
participant User as ユーザー
participant Router as ルーター
participant Guard as ガード群
participant Component as コンポーネント
User->>Router: ページ遷移要求
Router->>Guard: beforeEach実行
Guard->>Guard: 認証チェック
Guard->>Router: 遷移許可/拒否
Router->>Guard: beforeEnter実行
Guard->>Guard: ルート固有チェック
Router->>Component: beforeRouteEnter実行
Component->>Component: データプリロード
Router->>Guard: beforeResolve実行
Router->>Guard: afterEach実行
Guard->>User: ページ表示完了
遅延ロードの実装
遅延ロードを実装することで、アプリケーションの初期読み込み時間を大幅に短縮できます。
基本的な遅延ロード
最もシンプルな遅延ロードの実装です。矢印関数と dynamic import を使用します。
typescript// router/index.ts
const routes: RouteRecordRaw[] = [
{
path: '/',
name: 'Home',
// 同期的にインポート(推奨しない)
// component: Home
// 遅延ロード(推奨)
component: () => import('../views/Home.vue'),
},
];
この構文により、Webpack は自動的にコンポーネントを別ファイルに分割し、必要なときだけ読み込みます。
Webpack チャンク名の指定
関連するコンポーネントを同じチャンクにグループ化することで、効率的に読み込めます。
typescript// 関連ページをグループ化
const routes: RouteRecordRaw[] = [
{
path: '/user/profile',
name: 'UserProfile',
component: () =>
import(
/* webpackChunkName: "user" */
'../views/user/Profile.vue'
),
},
{
path: '/user/settings',
name: 'UserSettings',
component: () =>
import(
/* webpackChunkName: "user" */
'../views/user/Settings.vue'
),
},
{
path: '/admin/dashboard',
name: 'AdminDashboard',
component: () =>
import(
/* webpackChunkName: "admin" */
'../views/admin/Dashboard.vue'
),
},
];
この例では、ユーザー関連ページはuser.jsに、管理者ページはadmin.jsに分割されます。同じチャンク名を指定したコンポーネントは 1 つのファイルにバンドルされるのです。
Prefetch と Preload の活用
Webpack の特殊なコメントを使用して、事前読み込みを制御できます。
typescript// Prefetch - ブラウザのアイドル時に事前読み込み
const routes: RouteRecordRaw[] = [
{
path: '/dashboard',
name: 'Dashboard',
component: () =>
import(
/* webpackChunkName: "dashboard" */
/* webpackPrefetch: true */
'../views/Dashboard.vue'
),
},
];
Prefetch は、ブラウザがアイドル状態のときにリソースを事前読み込みします。ユーザーがアクセスする可能性が高いページに使用しましょう。
typescript// Preload - 親チャンクと並列で読み込み
const routes: RouteRecordRaw[] = [
{
path: '/critical',
name: 'Critical',
component: () =>
import(
/* webpackChunkName: "critical" */
/* webpackPreload: true */
'../views/Critical.vue'
),
},
];
Preload は親チャンクと並列で読み込まれ、優先度が高くなります。初期表示に必要なコンポーネントに使用します。
ネストされたルートの遅延ロード
親子関係のあるルートでも、それぞれ独立して遅延ロードできます。
typescriptconst routes: RouteRecordRaw[] = [
{
path: '/products',
component: () => import('../layouts/ProductLayout.vue'),
children: [
{
path: '',
name: 'ProductList',
component: () =>
import(
/* webpackChunkName: "products" */
'../views/products/List.vue'
),
},
{
path: ':id',
name: 'ProductDetail',
component: () =>
import(
/* webpackChunkName: "products" */
'../views/products/Detail.vue'
),
},
{
path: ':id/edit',
name: 'ProductEdit',
component: () =>
import(
/* webpackChunkName: "products-edit" */
'../views/products/Edit.vue'
),
},
],
},
];
親レイアウトとリスト・詳細は同じチャンクに、編集ページは別チャンクにすることで、適切に分割できますね。
エラーハンドリング
遅延ロードの失敗に備えて、エラーハンドリングを実装しましょう。
typescript// エラーハンドリング付き遅延ロード
const routes: RouteRecordRaw[] = [
{
path: '/dashboard',
name: 'Dashboard',
component: () =>
import('../views/Dashboard.vue').catch((err) => {
console.error(
'Failed to load Dashboard component:',
err
);
// フォールバックコンポーネントを返す
return import('../views/ErrorPage.vue');
}),
},
];
ネットワークエラーなどでコンポーネントの読み込みに失敗した場合、エラーページを表示できます。
次の図は、遅延ロードによるバンドル分割の効果を示しています。
mermaidflowchart TB
subgraph before["遅延ロード前"]
bundle1["app.js<br/>(5MB)<br/>全コンポーネント含む"]
end
subgraph after["遅延ロード後"]
bundle2["app.js<br/>(500KB)<br/>初期表示のみ"]
bundle3["user.js<br/>(200KB)"]
bundle4["admin.js<br/>(300KB)"]
bundle5["products.js<br/>(400KB)"]
end
before --> after
style bundle1 fill:#ffcccc
style bundle2 fill:#ccffcc
トランジションの実装
ページ遷移にトランジションを追加することで、ユーザー体験が大きく向上します。
基本的なトランジション設定
まず、ルータービューをトランジションコンポーネントでラップします。
vue<!-- App.vue -->
<template>
<router-view v-slot="{ Component }">
<transition name="fade" mode="out-in">
<component :is="Component" />
</transition>
</router-view>
</template>
次に、CSS でトランジションのスタイルを定義します。
css/* フェードトランジション */
.fade-enter-active,
.fade-leave-active {
transition: opacity 0.3s ease;
}
.fade-enter-from,
.fade-leave-to {
opacity: 0;
}
この設定により、ページ切り替え時にフェードイン・フェードアウトのアニメーションが適用されます。
スライドトランジション
より動きのあるスライドアニメーションを実装してみましょう。
vue<!-- App.vue -->
<template>
<router-view v-slot="{ Component, route }">
<transition name="slide" mode="out-in">
<component :is="Component" :key="route.path" />
</transition>
</router-view>
</template>
CSS でスライドアニメーションを定義します。
css/* スライドトランジション */
.slide-enter-active,
.slide-leave-active {
transition: all 0.3s ease;
}
.slide-enter-from {
transform: translateX(100%);
opacity: 0;
}
.slide-leave-to {
transform: translateX(-100%);
opacity: 0;
}
ルートごとに異なるトランジション
ルートのメタ情報を使用して、ページごとに異なるトランジションを適用できます。
typescript// router/index.ts
const routes: RouteRecordRaw[] = [
{
path: '/',
name: 'Home',
component: () => import('../views/Home.vue'),
meta: { transition: 'fade' },
},
{
path: '/about',
name: 'About',
component: () => import('../views/About.vue'),
meta: { transition: 'slide' },
},
];
コンポーネント側で動的にトランジション名を切り替えます。
vue<!-- App.vue -->
<template>
<router-view v-slot="{ Component, route }">
<transition
:name="route.meta.transition || 'fade'"
mode="out-in"
>
<component :is="Component" :key="route.path" />
</transition>
</router-view>
</template>
ネストされたトランジション
親子関係のあるルートで、それぞれ異なるトランジションを適用できます。
vue<!-- layouts/MainLayout.vue -->
<template>
<div class="layout">
<header>ヘッダー</header>
<main>
<router-view v-slot="{ Component }">
<transition name="nested-slide" mode="out-in">
<component :is="Component" />
</transition>
</router-view>
</main>
</div>
</template>
ネストされたトランジション用の CSS を定義します。
css/* ネストされたスライドトランジション */
.nested-slide-enter-active,
.nested-slide-leave-active {
transition: all 0.2s ease;
}
.nested-slide-enter-from {
transform: translateY(20px);
opacity: 0;
}
.nested-slide-leave-to {
transform: translateY(-20px);
opacity: 0;
}
JavaScript フックを使用した高度なトランジション
複雑なアニメーションには、JavaScript フックと GSAP などのライブラリを組み合わせます。
vue<!-- App.vue -->
<script setup lang="ts">
import { gsap } from 'gsap';
function onBeforeEnter(el: Element) {
gsap.set(el, {
opacity: 0,
y: 50,
});
}
function onEnter(el: Element, done: () => void) {
gsap.to(el, {
opacity: 1,
y: 0,
duration: 0.5,
ease: 'power2.out',
onComplete: done,
});
}
function onLeave(el: Element, done: () => void) {
gsap.to(el, {
opacity: 0,
y: -50,
duration: 0.3,
ease: 'power2.in',
onComplete: done,
});
}
</script>
<template>
<router-view v-slot="{ Component }">
<transition
mode="out-in"
@before-enter="onBeforeEnter"
@enter="onEnter"
@leave="onLeave"
>
<component :is="Component" />
</transition>
</router-view>
</template>
カスタムトランジションクラスの使用
Animate.css などの外部ライブラリを使用する場合、カスタムクラス名を指定できます。
vue<template>
<router-view v-slot="{ Component }">
<transition
mode="out-in"
enter-active-class="animate__animated animate__fadeInRight"
leave-active-class="animate__animated animate__fadeOutLeft"
>
<component :is="Component" />
</transition>
</router-view>
</template>
事前に Animate.css をインストールして読み込む必要があります。
bashyarn add animate.css
typescript// main.ts
import 'animate.css';
次の図は、トランジションのライフサイクルを示しています。
mermaidstateDiagram-v2
[*] --> BeforeEnter: 入場開始
BeforeEnter --> Enter: enter-from適用
Enter --> EnterActive: enter-active適用
EnterActive --> Entered: enter-to適用
Entered --> [*]: 入場完了
[*] --> BeforeLeave: 退出開始
BeforeLeave --> Leave: leave-from適用
Leave --> LeaveActive: leave-active適用
LeaveActive --> Left: leave-to適用
Left --> [*]: 退出完了
統合実装例
最後に、ガード、遅延ロード、トランジションを組み合わせた実践的な例を見てみましょう。
ルーター設定の完全版
すべての機能を統合したルーター設定です。
typescript// router/index.ts
import { createRouter, createWebHistory } from 'vue-router';
import type { RouteRecordRaw } from 'vue-router';
// ルート定義
const routes: RouteRecordRaw[] = [
{
path: '/',
name: 'Home',
component: () => import('../views/Home.vue'),
meta: {
transition: 'fade',
title: 'ホーム',
},
},
{
path: '/login',
name: 'Login',
component: () => import('../views/Login.vue'),
meta: {
transition: 'slide',
title: 'ログイン',
},
},
{
path: '/dashboard',
name: 'Dashboard',
component: () =>
import(
/* webpackChunkName: "dashboard" */
/* webpackPrefetch: true */
'../views/Dashboard.vue'
),
meta: {
requiresAuth: true,
transition: 'fade',
title: 'ダッシュボード',
},
beforeEnter: (to, from, next) => {
// ダッシュボード固有のチェック
const hasAccess = checkDashboardAccess();
hasAccess ? next() : next({ name: 'Home' });
},
},
];
// ルーターインスタンス
const router = createRouter({
history: createWebHistory(),
routes,
});
// グローバルガード
router.beforeEach((to, from, next) => {
const requiresAuth = to.matched.some(
(record) => record.meta.requiresAuth
);
const isAuthenticated = checkAuth();
if (requiresAuth && !isAuthenticated) {
next({
name: 'Login',
query: { redirect: to.fullPath },
});
} else {
next();
}
});
router.afterEach((to) => {
document.title = `${to.meta.title || 'ページ'} | My App`;
});
function checkAuth(): boolean {
return localStorage.getItem('token') !== null;
}
function checkDashboardAccess(): boolean {
const userRole = localStorage.getItem('userRole');
return userRole === 'admin' || userRole === 'user';
}
export default router;
この統合実装により、安全で高速、かつ美しいページ遷移が実現できます。
まとめ
Vue.js Router のナビゲーションガード、遅延ロード、トランジションは、モダンな SPA を構築するための必須技術です。
ナビゲーションガードにより、ページ遷移の各段階で認証チェックやデータプリロードを実行でき、安全で効率的なルーティングを実現できます。7 種類のガードを適切に使い分けることで、グローバルな制御からコンポーネント固有の処理まで、柔軟に対応できるでしょう。
遅延ロードは、アプリケーションのパフォーマンスを劇的に向上させます。動的 import と Webpack のマジックコメントを活用することで、初期バンドルサイズを削減し、ユーザーが必要とするコードだけを効率的に配信できますね。特に大規模アプリケーションでは、適切なコード分割が成功の鍵となります。
トランジションは、技術的な機能以上に、ユーザー体験の質を左右する重要な要素です。CSS トランジション、JavaScript フック、外部ライブラリの活用により、ブランドの個性を表現する洗練されたアニメーションを実装できるでしょう。
これら 3 つの機能を組み合わせることで、高速で安全、そして美しいユーザー体験を提供する Vue.js アプリケーションを構築できます。この記事の速見表と実装例を参考に、ぜひ実践してみてください。
関連リンク
articleVue.js Router 速見表:ガード・遅延ロード・トランジションの定石
articleVue.js Monorepo 構築:pnpm/Turborepo でアプリとパッケージを一元管理
articleVue.js ルーター戦略比較:ネスト/動的セグメント/ガードの設計コスト
articleVue.js でメモリリーク?watch/effect/イベント登録の落とし穴と検知法
articleVue.js リアクティビティ内部解剖:Proxy/ref/computed を図で読み解く
articleVue.js 本番運用チェックリスト:CSP/SRI/Cache-Control/エラーログの要点
articleZod 合成パターン早見表:`object/array/tuple/record/map/set/intersection` 実例集
articleバックアップ戦略の決定版:WordPress の世代管理/災害復旧の型
articleYarn 運用ベストプラクティス:lockfile 厳格化・frozen-lockfile・Bot 更新方針
articleWebSocket のペイロード比較:JSON・MessagePack・Protobuf の速度とコスト検証
articleWeb Components イベント設計チート:`CustomEvent`/`composed`/`bubbles` 実例集
articleWebRTC SDP 用語チートシート:m=・a=・bundle・rtcp-mux を 10 分で総復習
blogiPhone 17シリーズの発表!全モデルiPhone 16から進化したポイントを見やすく整理
blogGoogleストアから訂正案内!Pixel 10ポイント有効期限「1年」表示は誤りだった
blog【2025年8月】Googleストア「ストアポイント」は1年表記はミス?2年ルールとの整合性を検証
blogGoogleストアの注文キャンセルはなぜ起きる?Pixel 10購入前に知るべき注意点
blogPixcel 10シリーズの発表!全モデル Pixcel 9 から進化したポイントを見やすく整理
blogフロントエンドエンジニアの成長戦略:コーチングで最速スキルアップする方法
review今の自分に満足していますか?『持たざる者の逆襲 まだ何者でもない君へ』溝口勇児
reviewついに語られた業界の裏側!『フジテレビの正体』堀江貴文が描くテレビ局の本当の姿
review愛する勇気を持てば人生が変わる!『幸せになる勇気』岸見一郎・古賀史健のアドラー実践編で真の幸福を手に入れる
review週末を変えれば年収も変わる!『世界の一流は「休日」に何をしているのか』越川慎司の一流週末メソッド
review新しい自分に会いに行こう!『自分の変え方』村岡大樹の認知科学コーチングで人生リセット
review科学革命から AI 時代へ!『サピエンス全史 下巻』ユヴァル・ノア・ハラリが予見する人類の未来