【簡単】Vue Routerの基本を学ぼう!導入から使い方まで


【簡単】Vue Routerの基本を学ぼう!導入から使い方まで

はじめに:なぜシングルページアプリケーションにルーティングが必要なの?

Webサイトを開発する際、複数のページを持つことは一般的です。例えば、トップページ、製品一覧ページ、詳細ページ、お問い合わせページなどがあります。これらのページ間を移動する際には、通常、ブラウザがページ全体をリロードします。

しかし、Vue.jsのようなモダンなJavaScriptフレームワークを使って開発されるシングルページアプリケーション(SPA)では、通常、ページ全体のリロードは行いません。代わりに、ユーザーの操作(リンクのクリックなど)に応じて、JavaScriptが動的に表示内容を書き換えます。これにより、ページの切り替えが瞬時に行われ、デスクトップアプリケーションのような滑らかなユーザー体験を提供できます。

では、ページ全体のリロードなしに、どのようにして「このURLにアクセスしたらこの画面を表示する」「あのURLにアクセスしたらあの画面を表示する」というような、複数の「ページ」の状態を管理するのでしょうか?また、ブラウザの戻る/進むボタンに対応したり、特定のページへのブックマークやURL共有を可能にしたりするにはどうすれば良いのでしょうか?

ここで登場するのがルーティングです。特にSPAにおいては、JavaScript側でURLと表示するコンポーネントのマッピングを管理し、ブラウザの履歴APIなどを活用してURLの変化を検知・制御する仕組みが必要になります。

Vue.jsのエコシステムにおいて、このSPAのルーティング機能を提供する公式ライブラリがVue Routerです。Vue Routerを使えば、簡単に以下のようなことが実現できます。

  • URLに応じて表示するVueコンポーネントを切り替える
  • ブラウザの戻る/進むボタンに対応する
  • URLパラメータ(例:/products/123123)を使って動的にコンテンツを表示する
  • ネストされた(入れ子になった)ビューを扱う
  • ナビゲーション時の様々な処理(認証チェック、データ取得など)を行う

この記事では、Vue Routerの基本的な導入方法から、主要な機能、そして少し応用的な使い方までを、具体的なコード例を交えながら徹底的に解説します。この記事を読み終える頃には、あなたのVue.jsアプリケーションに効率的かつ強力なルーティング機能を実装できるようになっているはずです。

1. Vue Routerの導入

Vue RouterをVue.jsプロジェクトに導入する方法はいくつかありますが、最も一般的なのはnpmまたはyarnといったパッケージマネージャーを使う方法です。Vue CLIを使ってプロジェクトを作成した場合、プロジェクト作成時にVue Routerを含めるオプションを選択することもできます。

1.1 npm または yarn を使ったインストール

既存のVue.jsプロジェクトにVue Routerを追加する場合、プロジェクトのルートディレクトリで以下のコマンドを実行します。

“`bash

npmの場合

npm install vue-router@next

yarnの場合

yarn add vue-router@next
“`

ここで @next がついているのは、Vue 3に対応したVue Router v4をインストールするためです。Vue 2を使用している場合は @^3 を指定してください。この記事はVue 3とVue Router v4を前提に解説を進めます。

インストールが完了したら、プロジェクト内でVue Routerをインポートして使用できるようになります。

1.2 Vue CLI を使ったプロジェクト作成時の導入

Vue CLI (Vue Command Line Interface) を使って新しいプロジェクトを作成する際、対話形式のプロンプトで「Would you like to install Vue Router?」といった質問が出ます。ここで「Yes」を選択することで、プロジェクト作成時にVue Routerが自動的に設定された状態になります。

Vue CLIでVue Routerを導入すると、src ディレクトリ内に router というディレクトリが作成され、その中にルーティング設定ファイル(通常 index.js)やビューコンポーネント(例: views/HomeView.vue, views/AboutView.vue)が生成されます。これは学習を始める上で非常に便利です。

この記事では、手動でVue Routerを設定する場合と、Vue CLIで生成される構造の両方を想定し、コード例を提示していきます。

1.3 CDN を使った方法(簡単な紹介)

開発や簡単なテスト目的であれば、CDN経由でVue Routerを読み込むことも可能です。

“`html



“`

ただし、実際のアプリケーション開発ではパッケージマネージャーを使う方法が推奨されます。

2. Vue Routerの基本概念と設定

Vue Routerを使い始めるために必要な基本的な要素と設定方法を見ていきましょう。

2.1 ルーターインスタンスの作成 (createRouter)

まず、ルーティングの設定を管理する「ルーターインスタンス」を作成します。これはVue Routerの機能を使う上で中心となるオブジェクトです。

通常、プロジェクトの src ディレクトリ内に router ディレクトリを作成し、その中に index.js のようなファイルを作成してルーターの設定を集約します。

“`javascript
// src/router/index.js

import { createRouter, createWebHistory } from ‘vue-router’;

// ルート定義(後述)
const routes = [
// … ここにルート設定を記述 …
];

// ルーターインスタンスの作成
const router = createRouter({
// 履歴モードの設定 (後述)
history: createWebHistory(),
// ルート定義
routes,
});

// ルーターインスタンスをエクスポート
export default router;
“`

createRouter 関数を使ってルーターインスタンスを作成します。この関数には設定オブジェクトを渡します。最低限必要な設定は以下の2つです。

  • history: 履歴モードを指定します。ユーザーがどのURLにアクセスしたかを記録し、ブラウザの戻る/進むボタンに対応するために必要です。
  • routes: アプリケーションのルート定義を配列として指定します。

2.2 履歴モード (history vs hash)

history オプションでは、アプリケーションのURL履歴をどのように管理するかを指定します。主なモードは2つあります。

  1. createWebHistory() (HTML5 History API モード)

    • history: createWebHistory() のように設定します。
    • 例: https://example.com/users/123 のような、従来のWebサイトに近いクリーンなURLを使用します。
    • HTML5 History API (pushState, replaceState, popstate イベントなど) を利用します。
    • 利点: URLがクリーンで、検索エンジン最適化 (SEO) に有利な場合があります(SPAのSEOには別途考慮が必要ですが)。
    • 注意点: サーバ側の設定が必要です。SPAでは、どのURLに直接アクセスされても、必ずアプリケーションのエントリポイント(通常は index.html)を返すように設定する必要があります。そうでなければ、例えば /users/123 に直接アクセスした際に、サーバがそのパスに対応するファイルを見つけられず404エラーになってしまいます。ほとんどのモダンな開発サーバ(Vite, Webpack Dev Serverなど)は開発時には自動的にこの設定をシミュレートしてくれますが、本番環境にデプロイする際にはWebサーバ(Apache, Nginxなど)やホスティングサービス側の設定が必要です。
  2. createWebHashHistory() (Hash モード)

    • history: createWebHashHistory() のように設定します。
    • 例: https://example.com/#/users/123 のように、URLのフラグメント識別子(# の後に続く部分)を利用します。
    • # 以降の部分はブラウザによってサーバに送信されないため、サーバ側の特別な設定は不要です。
    • 利点: サーバ側の設定が不要で、静的なファイルサーバでも動作します。
    • 注意点: URLに # が含まれます。一部の古いブラウザや、フラグメント識別子の扱いに違いがある環境で予期しない挙動を示す可能性がゼロではありません。SEOの観点では、クリーンなURLを持つHistoryモードが推奨されることが多いです。

特別な理由がなければ、モダンなWebアプリケーションでは createWebHistory() を使用するのが一般的です。本番環境でのサーバ設定が必要になることだけ覚えておいてください。

2.3 ルート定義 (routes 配列)

routes オプションは、アプリケーションのすべてのルート(パスとそれに対応するコンポーネントのマッピング)を定義するJavaScriptオブジェクトの配列です。配列の各要素は一つのルート設定オブジェクトです。

ルート設定オブジェクトには、少なくとも以下のプロパティが必要です。

  • path: このルートにマッチするURLパスを指定します。文字列です。
  • component: このルートにマッチしたときに表示されるVueコンポーネントを指定します。

“`javascript
// src/router/index.js (routes 配列の例)

import { createRouter, createWebHistory } from ‘vue-router’;

// 表示するコンポーネントをインポート
// 通常は別ファイルにコンポーネントを定義します
import HomeView from ‘../views/HomeView.vue’;
import AboutView from ‘../views/AboutView.vue’;
import ProductList from ‘../components/ProductList.vue’;
import ProductDetail from ‘../components/ProductDetail.vue’;

const routes = [
{
path: ‘/’, // パス ‘/’ (ルートパス) にマッチ
name: ‘home’, // このルートの名前 (後述)
component: HomeView, // マッチしたら HomeView コンポーネントを表示
},
{
path: ‘/about’, // パス ‘/about’ にマッチ
name: ‘about’,
component: AboutView, // マッチしたら AboutView コンポーネントを表示
},
{
path: ‘/products’, // パス ‘/products’ にマッチ
name: ‘products’,
component: ProductList, // マッチしたら ProductList コンポーネントを表示
},
{
// 動的セグメント (後述)
path: ‘/products/:id’, // 例: /products/123 にマッチ
name: ‘product-detail’,
component: ProductDetail, // マッチしたら ProductDetail コンポーネントを表示
},
// 404 catch-all ルート (後述)
// {
// path: ‘/:pathMatch(.)‘,
// name: ‘not-found’,
// component: NotFoundView,
// }
];

const router = createRouter({
history: createWebHistory(),
routes,
});

export default router;
“`

2.4 ルートコンポーネント

routes 配列で component に指定するVueコンポーネントです。これらのコンポーネントは、特定のURLにアクセスされたときにメインコンテンツとして表示されます。

例: src/views/HomeView.vue

“`vue

“`

2.5 <router-view> コンポーネント (プレースホルダー)

アプリケーションのレイアウトテンプレート(通常は src/App.vue)には、<router-view> という特殊なコンポーネントを配置します。これは、現在のルートにマッチしたコンポーネント(ルートコンポーネント)が実際に表示される場所の「プレースホルダー」として機能します。

アプリケーションの主要なコンポーネントツリーは常に描画されており、<router-view> の部分だけが、現在のURLに対応するルートコンポーネントに置き換えられるイメージです。

“`vue

“`

2.6 <router-link> コンポーネント (ナビゲーションリンク)

アプリケーション内でルーティングによるページ遷移を行うためのリンクを生成するには、通常の <a href="..."> タグではなく、Vue Routerが提供する <router-link> コンポーネントを使用します。

<router-link> は、クリックされるとブラウザのページリロードを引き起こすことなく、指定されたURLへのSPA内部でのナビゲーションを行います。そして、ブラウザのHistory APIを適切に操作してURLを更新し、履歴スタックに新しいエントリを追加します。

基本的な使い方は、遷移先のパスを :to プロパティにバインドすることです。

html
<router-link to="/">Home</router-link>
<router-link to="/about">About</router-link>
<router-link :to="'/products/' + productId">商品詳細</router-link> <!-- 動的にパスを生成 -->

<router-link> は、最終的に通常の <a> タグとしてレンダリングされます。href 属性は :to に指定したパスに基づいて自動的に生成されます。

また、<router-link> には、現在のURLとマッチしている場合に自動的に特定のCSSクラスが付与される機能があります。デフォルトでは router-link-activerouter-link-exact-active というクラスが付与されます(これらのクラス名はルーターオプションで変更可能です)。これを利用して、現在表示しているページのリンクをハイライト表示することができます。上記の App.vue<style> セクションでは、このクラスを使ってアクティブなリンクの色を変えています。

2.7 アプリケーションへのルーターの組み込み

作成したルーターインスタンスをVueアプリケーションに組み込む必要があります。これは通常、アプリケーションのエントリポイントファイル(例: src/main.js または src/main.ts)で行います。

“`javascript
// src/main.js

import { createApp } from ‘vue’;
import App from ‘./App.vue’;
import router from ‘./router’; // 作成したルーター設定をインポート

const app = createApp(App);

// router.js でエクスポートしたルーターインスタンスを use() メソッドでアプリケーションにインストール
app.use(router);

// アプリケーションをマウント
app.mount(‘#app’);
“`

app.use(router) を呼び出すことで、Vueアプリケーション全体で $router (ルーターインスタンス自体) と $route (現在のルート情報) というグローバルなプロパティが利用可能になり、<router-view><router-link> といったVue Routerのコンポーネントが登録され使えるようになります。

これで、Vue Routerを使うための基本的な設定は完了です。

3. 基本的なルーティングの実装例

ここまでで学んだ基本概念を使って、簡単なアプリケーションのルーティングを実装してみましょう。

ファイル構成例:

my-vue-app/
├── src/
│ ├── main.js
│ ├── App.vue
│ ├── router/
│ │ └── index.js
│ └── views/
│ ├── HomeView.vue
│ └── AboutView.vue
│ └── components/
│ └── ... (他のコンポーネント)
├── package.json
└── index.html

src/router/index.js:

“`javascript
import { createRouter, createWebHistory } from ‘vue-router’;
import HomeView from ‘../views/HomeView.vue’;
import AboutView from ‘../views/AboutView.vue’;

const routes = [
{
path: ‘/’,
name: ‘home’,
component: HomeView,
},
{
path: ‘/about’,
name: ‘about’,
component: AboutView,
},
];

const router = createRouter({
history: createWebHistory(process.env.BASE_URL), // Historyモードを使用
routes,
});

export default router;
``
*補足:
process.env.BASE_URLは、もしアプリケーションがサブディレクトリ(例:https://example.com/my-app/`)にデプロイされる場合に備えて、ベースとなるパスを指定する環境変数です。必須ではありませんが、プロダクション環境で利用する可能性があれば含めておくと良いでしょう。*

src/views/HomeView.vue:

“`vue

“`

src/views/AboutView.vue:

“`vue

“`

src/App.vue:

“`vue

“`

src/main.js:

“`javascript
import { createApp } from ‘vue’;
import App from ‘./App.vue’;
import router from ‘./router’; // router/index.js をインポート

createApp(App).use(router).mount(‘#app’);
“`

この設定により、アプリケーションを起動すると:

  • ブラウザで http://localhost:xxxx/ にアクセスすると、HomeView.vue の内容が <router-view> の部分に表示されます。ナビゲーションリンクの “Home” がアクティブになります。
  • “About” リンクをクリックするか、ブラウザで http://localhost:xxxx/about にアクセスすると、AboutView.vue の内容が <router-view> の部分に表示されます。ナビゲーションリンクの “About” がアクティブになります。
  • ブラウザの戻る/進むボタンも正常に機能します。

これがVue Routerを使った最も基本的なルーティングの仕組みです。

4. 動的ルーティング

アプリケーションには、詳細ページのように、URLの一部が動的に変わるようなルートがよくあります。例えば、ユーザー詳細ページであれば /users/1/users/2、商品詳細ページであれば /products/abc/products/xyz のように、IDやスラッグといった識別子がURLに含まれるケースです。

Vue Routerでは、このような動的なセグメントを持つルートを簡単に定義できます。

4.1 パスパラメータ (:idなど) の使い方

ルートの path プロパティで、 : の後にセグメント名(例: :id, :slug)を記述することで、その部分を動的なパラメータとして扱えます。

javascript
// src/router/index.js
const routes = [
// ... その他のルート ...
{
path: '/products/:productId', // :productId が動的なパラメータ
name: 'product-detail',
component: ProductDetail,
},
{
path: '/users/:userId/posts/:postId', // 複数のパラメータも定義可能
name: 'user-post',
component: UserPost,
},
];

この設定で、例えば /products/123 というURLにアクセスした場合、:productId の部分が 123 として認識されます。

4.2 コンポーネント内でのパスパラメータの取得方法 ($route.params)

マッチしたルートのパスパラメータは、そのルートコンポーネント内で $route.params オブジェクトを通じて取得できます。

“`vue

“`

<script> 部分のコメントアウトされたコードは、パラメータ変更への対応や、props オプションを使ったパラメータの受け渡し方法を示しています。特に同じコンポーネントでパラメータだけが変更される(例: /products/1 から /products/2 への遷移)際には、パラメータ変更を検知してデータを再取得するロジックが必要不可欠です。

4.3 props オプションを使ったパラメータの受け渡し(推奨)

コンポーネント内で $route.params を直接参照すると、コンポーネントが特定のURL構造に強く依存してしまい、再利用性が低下します。よりクリーンな方法として、ルート定義で props: true を指定し、パスパラメータをコンポーネントのpropsとして受け取る方法が推奨されます。

src/router/index.js での設定:

javascript
const routes = [
{
path: '/products/:productId',
name: 'product-detail',
component: ProductDetail,
props: true, // これを追加! パスパラメータをpropsとして渡す
},
// 複数のパラメータをオブジェクト形式で渡すことも可能
// {
// path: '/users/:userId/posts/:postId',
// name: 'user-post',
// component: UserPost,
// props: (route) => ({ // 関数として定義すると、より柔軟に渡せる
// userId: route.params.userId,
// postId: route.params.postId,
// // クエリパラメータなども渡せる
// // category: route.query.category
// }),
// },
];

src/components/ProductDetail.vue での受け取り:

“`vue

“`

props: true を使うことで、コンポーネントは $route.params に依存することなく、単に productId というpropsを受け取るコンポーネントとして扱えます。これにより、この ProductDetail コンポーネントを、ルーティング経由でなく、親コンポーネントから直接 productId をpropsとして渡して表示するといった再利用が可能になります。これはVue.jsのコンポーネント設計において非常に重要なプラクティスです。

ほとんどの場合、props: true を使うのが最も推奨される方法です。複数のパラメータやクエリパラメータなどもまとめてpropsとして渡したい場合は、props に関数を指定する方法が便利です。

5. ネストされたルーティング (Nested Routes)

アプリケーションのUIは、しばしばネストされた構造になります。例えば、ユーザー設定画面の中に「プロフィール設定」「アカウント設定」「通知設定」といったサブセクションがあり、それぞれのURLが /settings/profile/settings/account/settings/notifications のようになる場合です。

Vue Routerでは、このような構造を children プロパティを使って表現できます。

5.1 親子ルートの定義 (children プロパティ)

ルート定義オブジェクトは、children という配列プロパティを持つことができます。この children 配列に指定されたルートは、親ルートのパスに相対的なパスとして扱われます。

“`javascript
// src/router/index.js

import SettingsLayout from ‘../views/SettingsLayout.vue’; // 親コンポーネント
import ProfileSettings from ‘../components/ProfileSettings.vue’; // 子コンポーネント
import AccountSettings from ‘../components/AccountSettings.vue’;
import NotificationSettings from ‘../components/NotificationSettings.vue’;

const routes = [
// … その他のルート …
{
path: ‘/settings’, // 親ルートのパス
name: ‘settings’,
component: SettingsLayout, // この親ルートにマッチしたときに表示されるコンポーネント

children: [ // ここにネストされた子ルートを定義
  {
    // 子ルートのパスは親ルートのパスに相対的
    // この場合、フルパスは '/settings/profile' になる
    path: 'profile', // パスの先頭に / は付けない!
    name: 'settings-profile',
    component: ProfileSettings,
  },
  {
    path: 'account', // フルパス '/settings/account'
    name: 'settings-account',
    component: AccountSettings,
  },
  {
    path: 'notifications', // フルパス '/settings/notifications'
    name: 'settings-notifications',
    component: NotificationSettings,
  },
  // 子ルートにも動的セグメントを含めることができる
  // {
  //   path: 'items/:itemId', // フルパス '/settings/items/:itemId'
  //   name: 'settings-item-detail',
  //   component: SettingsItemDetail,
  //   props: true, // props オプションも使える
  // }
  // 親ルートがマッチしたとき、子ルートのパスがどれにもマッチしない場合のデフォルト子ルート
  // path: '' とすることで、'/settings' にアクセスした場合にこのルートがマッチする
  {
     path: '', // フルパス '/settings'
     name: 'settings-overview', // または好きな名前
     redirect: { name: 'settings-profile' } // 例えばデフォルトでプロフィール設定にリダイレクト
  }
],

},
];
“`

5.2 親コンポーネント内の <router-view>

ネストされたルートが機能するためには、親ルートコンポーネント(上記の例では SettingsLayout.vue)の中に、さらに <router-view> を配置する必要があります。この親コンポーネント内の <router-view> は、現在マッチしている子ルートコンポーネントを表示するためのプレースホルダーとなります。

“`vue

“`

この設定により、ユーザーが例えば /settings/account にアクセスした場合:

  1. まず、path: '/settings' がマッチします。
  2. 対応する SettingsLayout.vue コンポーネントがトップレベルの <router-view> に表示されます。
  3. 次に、親パス /settings に対して相対的な path: 'account' がマッチします。
  4. 対応する AccountSettings.vue コンポーネントが SettingsLayout.vue 内の <router-view> に表示されます。

ネストされたルーティングは、複雑なレイアウトやUI構造を持つアプリケーションで非常に役立ちます。

6. 名前付きルート (Named Routes)

ルートに名前をつけることで、URLパスの代わりに名前を使ってナビゲーションやルートの特定ができるようになります。これは、URLパスが変更された場合でも、名前が変わらなければナビゲーションコードを修正する必要がないため、メンテナンス性を向上させます。

6.1 ルートに名前をつける (name プロパティ)

ルート定義オブジェクトに name プロパティを追加するだけです。名前はアプリケーション内でユニークである必要があります。

javascript
const routes = [
{
path: '/',
name: 'home', // 名前の定義
component: HomeView,
},
{
path: '/about',
name: 'about', // 名前の定義
component: AboutView,
},
{
path: '/products/:productId',
name: 'product-detail', // 名前の定義 (動的ルートにもつけられる)
component: ProductDetail,
props: true,
},
// ネストされたルートにも名前をつけられる
{
path: '/settings',
component: SettingsLayout,
children: [
{
path: 'profile',
name: 'settings-profile', // 子ルートの名前
component: ProfileSettings,
},
// ... 他の子ルート ...
],
},
];

6.2 <router-link> で名前を使って遷移する方法

<router-link>:to プロパティに、文字列パスの代わりに名前とパラメータを含むオブジェクトをバインドします。

“`html

Home
About
商品詳細

Home
About


商品詳細 ({{ someProductId }})

プロフィール設定
“`

名前付きルートを使うと、パスが /product/:productId から例えば /items/:productId に変更されても、name: 'product-detail' が変わらなければ <router-link>:to オブジェクトを変更する必要がありません。これはアプリケーションが大きくなるにつれて非常に大きなメリットとなります。

6.3 router.push で名前を使って遷移する方法

プログラムによるナビゲーション(後述)でも、パス文字列の代わりに名前付きルートオブジェクトを使用できます。

``javascript
// パス文字列で遷移
router.push('/about');
router.push(
/products/${someProductId}`);

// 名前付きルートで遷移
router.push({ name: ‘about’ });
router.push({ name: ‘product-detail’, params: { productId: someProductId } });

// クエリパラメータやハッシュを追加する場合
router.push({
name: ‘product-detail’,
params: { productId: someProductId },
query: { filter: ‘new’ }, // /products/123?filter=new のようになる
hash: ‘#description’ // /products/123#description のようになる
});
“`

6.4 名前付きルートのメリット

  • メンテナンス性向上: URL構造が変わっても、名前が変わらなければナビゲーションコードを変更する必要がない。
  • パラメータの扱い: 動的なパラメータをオブジェクト形式で渡しやすくなる。
  • 可読性: ルートの目的が名前で明確になる。

特別な理由がない限り、ほとんどのルートに名前をつけることが推奨されます。

7. 名前付きビュー (Named Views)

ここまでの例では、アプリケーションのメインレイアウト(通常は App.vue)に <router-view> が一つだけ配置されていました。しかし、アプリケーションのレイアウトによっては、同時に複数のビューコンポーネントを表示したい場合があります。例えば、サイドバー、ヘッダー、フッター、そしてメインコンテンツといった領域があり、それぞれの領域に特定のルートコンポーネントを表示したい場合です。

Vue Routerでは、<router-view> に名前をつけることで、この要件に対応できます。

7.1 複数の <router-view> を持つレイアウト

まず、複数の <router-view> をレイアウトコンポーネントに配置し、それぞれに name プロパティを指定します。名前を指定しない <router-view> は「デフォルト」ビューとして扱われます。

“`vue

“`

7.2 ルート定義での components オプション

複数の名前付きビューに対応するコンポーネントを指定するには、ルート定義で component プロパティの代わりに components プロパティを使用します。components はオブジェクトであり、キーにビューの名前(またはデフォルトビューの場合は 'default')、値に対応するコンポーネントを指定します。

“`javascript
// src/router/index.js

import ComplexLayout from ‘../views/ComplexLayout.vue’;
// 各ビューに表示するコンポーネント
import MainContent from ‘../components/MainContent.vue’;
import SidebarContent from ‘../components/SidebarContent.vue’;
import HeaderContent from ‘../components/HeaderContent.vue’;
import FooterContent from ‘../components/FooterContent.vue’;
import AboutMain from ‘../components/AboutMain.vue’;

const routes = [
// … その他のルート …
{
path: ‘/dashboard’,
name: ‘dashboard’,
// component: ComplexLayout, // 単一コンポーネントではない
components: { // components プロパティを使用
default: ComplexLayout, // デフォルトビューにレイアウトコンポーネントを表示
// ここで LayoutComponent の中にさらに router-view があれば、ネストされたビューも定義できる
// default: MainContent, // ComplexLayout をルートコンポーネントにせず、
// // App.vue のデフォルト router-view に MainContent を表示し、
// // ComplexLayout 内の router-view に別のコンポーネントを表示することも可能
},
children: [
{
path: ”, // /dashboard にマッチ
name: ‘dashboard-main’,
components: { // ComplexLayout 内の名前付きビューにコンポーネントを割り当てる
default: MainContent, // ComplexLayout のデフォルト router-view に表示
sidebar: SidebarContent, // ComplexLayout の router-view name=”sidebar” に表示
header: HeaderContent, // ComplexLayout の router-view name=”header” に表示
footer: FooterContent, // ComplexLayout の router-view name=”footer” に表示
},
// props: { // 名前付きビューごとに props を渡す場合
// default: true, // MainContent にパラメータをpropsとして渡す
// sidebar: { userSpecific: true }, // SidebarContent に固定の props を渡す
// }
},
{
path: ‘about’, // /dashboard/about にマッチ
name: ‘dashboard-about’,
components: {
default: AboutMain, // メインコンテンツだけ変更
sidebar: SidebarContent, // サイドバーは同じものを表示し続ける
header: HeaderContent,
footer: FooterContent,
},
},
// 他のダッシュボード内のセクション…
],
},
];
“`

この例では、'/dashboard' ルートにアクセスすると、まず App.vue のデフォルト <router-view>ComplexLayout.vue が表示されます。そして、ComplexLayout.vue 内の各名前付き <router-view> に、子ルート /dashboard (パスが空 '') に対応する components オブジェクトで指定されたコンポーネント(MainContent, SidebarContent, HeaderContent, FooterContent)が表示されます。

/dashboard/about にアクセスすると、ComplexLayout はそのままに、メインコンテンツ部分だけが AboutMain コンポーネントに切り替わります。

名前付きビューは、アプリケーション全体で共通のレイアウトを持ちつつ、URLや状態によって各部分の表示内容を細かく制御したい場合に非常に強力です。

注意点:

  • 複数のビューを持つルートにパラメータをpropsとして渡す場合、props オプションもオブジェクトとして指定し、各ビュー名に対して true または関数を指定する必要があります。
  • 名前付きビューは、多くの場合、ネストされたルーティングと組み合わせて使用されます。親ルートの components でレイアウトコンポーネントを指定し、そのレイアウトコンポーネント内の <router-view> に子ルートの components でコンテンツコンポーネントを割り当てるというパターンが一般的です。

8. プログラムによるナビゲーション

ユーザーが <router-link> をクリックする以外にも、JavaScriptコードの中で明示的にページ遷移を行いたい場合があります。例えば、フォームを送信した後、成功ページにリダイレクトしたい、ログイン後にダッシュボードに移動したい、といったケースです。

Vue Routerでは、ルーターインスタンスのメソッドを使ってプログラムによるナビゲーションを実行できます。ルーターインスタンスは、コンポーネント内では this.$router または Composition API の useRouter() フックで取得できます。

“`javascript
// Options API の場合
export default {
methods: {
goToAboutPage() {
// /about に遷移する
this.$router.push(‘/about’);
}
}
};

// Composition API の場合
import { useRouter } from ‘vue-router’;

export default {
setup() {
const router = useRouter();

const goToHomePage = () => {
  // 名前付きルートを使ってホームに遷移
  router.push({ name: 'home' });
};

return {
  goToHomePage
};

}
};
“`

最もよく使われるナビゲーションメソッドは以下の通りです。

8.1 router.push()

指定したパスまたは名前付きルートにナビゲーションし、新しい履歴エントリをブラウザの履歴スタックに追加します。ブラウザの「進む」ボタンでそのページに戻れるようになります。<router-link> をクリックしたときと同じ挙動です。

引数には、パス文字列または名前付きルートオブジェクトを指定できます。

“`javascript
// 文字列パス
router.push(‘/users/123’);
router.push(‘/users/123?page=2#profile’); // クエリパラメータやハッシュも指定可能

// 名前付きルートオブジェクト
router.push({ name: ‘user’, params: { userId: 123 } });
router.push({
name: ‘user’,
params: { userId: 123 },
query: { page: 2 },
hash: ‘#profile’
});

// 相対的なパス
router.push(‘profile’); // 現在のルートが /user/123 なら /user/123/profile へ遷移
router.push(‘./profile’); // 上記と同じ
router.push(‘../’); // 親ルートへ遷移 (例: /user/123/post/456 から /user/123 へ)
“`

8.2 router.replace()

push() と似ていますが、新しい履歴エントリを追加する代わりに、現在の履歴エントリを指定したパス/ルートで置き換えます。ブラウザの「戻る」ボタンで、置き換えられたページではなくその前のページに戻ることになります。リダイレクトのような挙動を実現したい場合に便利です。

javascript
// ログイン後にユーザー詳細ページへ遷移し、ログインページへ戻れないようにする
router.replace({ name: 'user-detail', params: { userId: loggedInUserId } });

引数は push() と同じです。

8.3 router.go(n)

履歴スタック内を n ステップ移動します。

  • router.go(1): 履歴を1つ進む (router.forward() と同じ)
  • router.go(-1): 履歴を1つ戻る (router.back() と同じ)
  • router.go(5): 履歴を5つ進む
  • router.go(-100): 履歴の最初に戻ろうとする(可能であれば)

8.4 router.back() および router.forward()

それぞれ履歴スタックを1つ戻る、または1つ進むための便利なメソッドです。router.go(-1)router.go(1) のエイリアスです。

javascript
router.back(); // 戻る
router.forward(); // 進む

8.5 router.resolve(to)

ナビゲーションは実行せず、指定されたルート情報 (to オブジェクト/文字列) に基づいて解決されたURLパス、ルート情報、ハッシュなどを取得します。<router-link>href 属性を動的に生成したい場合などに利用できます。

“`javascript
const resolved = router.resolve({ name: ‘product-detail’, params: { productId: 456 } });

console.log(resolved.href); // 例えば “/products/456”
console.log(resolved.route); // マッチしたルートオブジェクト
console.log(resolved.location); // 渡した to オブジェクト
console.log(resolved.htmlReady()); // true (HTMLレンダリング準備完了か)
“`

プログラムによるナビゲーションは、アプリケーションのインタラクションに応じて柔軟な画面遷移を実現するために不可欠な機能です。

9. リダイレクトとエイリアス

特定のパスへのアクセスを別のパスに転送したり、複数のパスで同じコンポーネントを表示させたい場合があります。Vue Routerは、ルート定義でこれらを簡単に設定できます。

9.1 リダイレクト (redirect オプション)

あるパスにアクセスされたときに、自動的に別のパスにリダイレクトさせます。ルート定義に redirect プロパティを追加します。

javascript
const routes = [
// ...
{
path: '/old-products', // このパスにアクセスすると
redirect: '/products', // /products にリダイレクトされる (パス文字列)
},
{
path: '/legacy-about',
// 名前付きルートへリダイレクト
redirect: { name: 'about' },
},
{
path: '/items/:id',
// パラメータを保持してリダイレクト
redirect: to => {
// to オブジェクトは現在のルート情報を含む
// 例: /items/123 にアクセス -> /products/123 にリダイレクト
return { name: 'product-detail', params: { productId: to.params.id } };
},
},
// デフォルト子ルートへのリダイレクト (ネストされたルーティングの例で示したもの)
// {
// path: '/settings',
// component: SettingsLayout,
// children: [
// { path: '', redirect: { name: 'settings-profile' } }, // /settings にアクセスしたら /settings/profile へ
// // ... 他の子ルート ...
// ],
// },
];

redirect は、パス文字列、名前付きルートオブジェクト、または現在のルート情報 (to) を受け取る関数として指定できます。関数形式のリダイレクトは、動的なリダイレクトやパラメータの引き継ぎに便利です。

リダイレクトは、ブラウザのURLバーが新しいURLに変わります。履歴スタックには、元のパスのエントリは残らず、直接リダイレクト先のパスのエントリが追加されます(History APIの場合)。

9.2 エイリアス (alias オプション)

エイリアスは、複数のパスを同じルートコンポーネントにマッピングしたい場合に使用します。指定されたエイリアスパスにアクセスしても、URLバーのパスは元のルートパスのままです。ブラウザの履歴にもエイリアスパスではなく元のルートパスが記録されます。

javascript
const routes = [
// ...
{
path: '/users/:userId', // メインのパス
name: 'user',
component: UserDetail,
alias: '/profile/:userId', // このパスにアクセスしても、表示されるのは UserDetail コンポーネントだが、
// URLバーは /profile/:userId のまま
},
{
path: '/products/:productId',
name: 'product-detail',
component: ProductDetail,
// 複数のエイリアスを指定する場合
alias: ['/item/:productId', '/product/:productId/details'],
},
];

この設定で、/profile/123 というURLにアクセスすると、URLは /profile/123 のままですが、UserDetail コンポーネントが表示され、そのコンポーネント内では $route.params.userId123 となります。これは /users/123 にアクセスした場合と同じコンポーネントが表示されるのとは対照的です。

エイリアスは、既存のURL構造を維持しつつ、新しいURL構造も導入したい場合や、ある特定のコンポーネントに複数のアクセスパスを提供したい場合に便利です。リダイレクトとは異なり、エイリアスはURLバーの表示を変更しません。

10. ナビゲーションガード (Navigation Guards)

ナビゲーションガードは、ルート遷移の過程で特定の処理(認証チェック、データの事前取得、確認ダイアログの表示など)を実行するための機能です。Vue Routerは、ルート遷移の様々な段階で呼び出されるガードを提供しています。

主に以下の3種類のガードがあります。

  • グローバルガード: アプリケーション全体のあらゆるルート遷移に対して実行されます。
  • ルート単位ガード: 特定のルート定義に直接設定するガードです。
  • コンポーネント単位ガード: ルートコンポーネント自身の中に定義するガードです。

10.1 グローバルガード

ルーターインスタンスに直接メソッドを呼び出して登録します。

  • router.beforeEach((to, from, next) => { ... }): 遷移前に呼び出されるグローバルガード。最も一般的で強力なガードです。どのルートからどのルートへ遷移しようとしているかをチェックし、遷移を許可、キャンセル、または別の場所へリダイレクトできます。
  • router.beforeResolve((to, from, next) => { ... }): beforeEach の直後、かつすべてのコンポーネント内ガード (beforeRouteEnter) が解決された後、ナビゲーションが完了する直前に呼び出されます。非同期ルーティングコンポーネントが解決されるのを待ってから実行したいロジックに適しています。
  • router.afterEach((to, from, failure) => { ... }): 遷移が完了した後に呼び出されるグローバルガード。遷移がキャンセルされたりエラーが発生した場合は failure 引数にエラー情報が含まれます。アナリティクスの記録やページのタイトル変更などに使用されます。next() は使用できません。

ガード関数の引数:

ほとんどのガード関数は以下の引数を受け取ります。

  • to: 遷移先のルートオブジェクト。パス、名前、パラメータ、クエリなどが含まれます。
  • from: 遷移元のルートオブジェクト
  • next: ナビゲーションを制御するために呼び出す関数
    • next(): ナビゲーションをそのまま進めます。
    • next(false): 現在のナビゲーションを中止します。URLは変更されません。
    • next('/path') または next({ name: 'route-name', ... }): 指定したパスまたはルートにリダイレクトします。現在のナビゲーションは破棄され、新しいナビゲーションが開始されます。
    • next(error): ナビゲーションを中止し、エラーハンドラにエラーを渡します。

next() は必ず一度だけ呼び出す必要があります。非同期処理を行う場合は、非同期処理が完了した後に next() を呼び出します。

グローバル beforeEach ガードの例 (簡易認証チェック):

“`javascript
// src/router/index.js

const routes = [
// … (ルート定義) …
{
path: ‘/dashboard’,
name: ‘dashboard’,
component: DashboardView,
meta: { requiresAuth: true } // メタフィールドを使って認証が必要なルートをマーク
},
{
path: ‘/login’,
name: ‘login’,
component: LoginView,
},
];

const router = createRouter({
history: createWebHistory(),
routes,
});

// グローバル beforeEah ガードを登録
router.beforeEach((to, from, next) => {
console.log(Navigating from ${from.path} to ${to.path});

// ダミーの認証チェック関数
const isAuthenticated = () => {
// 実際には localStorage, Vuex store, APIコールなどでチェック
return localStorage.getItem(‘isAuthenticated’) === ‘true’;
};

const requiresAuth = to.meta.requiresAuth; // 遷移先のルートに requiresAuth メタフィールドがあるかチェック

if (requiresAuth && !isAuthenticated()) {
// 認証が必要で、認証されていない場合
console.log(‘Authentication required. Redirecting to login.’);
// ログインページにリダイレクトし、リダイレクト元のパスをクエリパラメータとして渡す
next({
name: ‘login’,
query: { redirect: to.fullPath },
});
} else {
// 認証が不要なルート、または認証が必要で認証済みの場合
console.log(‘Navigation allowed.’);
next(); // そのまま遷移を許可
}
});

// afterEach ガードの例 (ページタイトル変更)
router.afterEach((to, from) => {
// to.meta.title などを使って動的にタイトルを変更
document.title = to.meta.title ? ${to.meta.title} - My App : ‘My App’;
});

export default router;
“`

この例では、ルート定義に meta: { requiresAuth: true } を追加することで、そのルートが認証を必要とすることをマークしています。beforeEach ガード内で、遷移先のルートに requiresAuth が設定されていて、かつユーザーが認証されていなければ、ログインページにリダイレクトしています。ログイン成功後、クエリパラメータの redirect を見て元のページに戻るようなロジックをログインコンポーネントに実装すると、より良いユーザー体験を提供できます。

10.2 ルート単位ガード (beforeEnter)

特定のルートだけに適用されるガードです。ルート定義の中に直接 beforeEnter プロパティとして関数を指定します。

“`javascript
const routes = [
// …
{
path: ‘/admin’,
name: ‘admin’,
component: AdminDashboard,
meta: { requiresAdmin: true },
beforeEnter: (to, from, next) => {
// このガードはこの ‘/admin’ ルートにアクセスする前にだけ実行される
console.log(‘Entering admin route…’);
const isAdmin = () => { / 管理者権限チェック / return true; };

  if (isAdmin()) {
    next(); // 管理者なら遷移許可
  } else {
    alert('管理者権限が必要です。');
    next(false); // 遷移中止
  }
},

},
// …
];
“`

beforeEnter ガードは、グローバル beforeEach ガードの後に実行されます。特定のルートに関するチェックを集約したい場合に便利です。子ルートを持つ親ルートに beforeEnter を設定した場合、そのガードは子ルートへのアクセス時にも親パスがマッチするため実行されます。

10.3 コンポーネント単位ガード

ルートコンポーネント自身の中に定義するガードです。

  • beforeRouteEnter(to, from, next): ルートコンポーネントが生成される前に呼び出されます。この時点ではコンポーネントインスタンスが存在しないため、this にアクセスできません。コンポーネントインスタンスにアクセスしたい場合は、next() にコールバック関数を渡します (next(vm => { /* vm はコンポーネントインスタンス */ }))。データ取得など、コンポーネントがマウントされる前に処理を完了させたい場合に有効です。
  • beforeRouteUpdate(to, from, next): 現在表示されているルートコンポーネントが再利用され、かつルートのパラメータやクエリが変更されたときに呼び出されます。例えば、/users/1 から /users/2 へ遷移する際に、UserDetail コンポーネントが再利用される場合などです。このガードは this にアクセスできます。コンポーネントの watch プロパティや watchEffect と同様に、パラメータ変更に応じたデータ再フェッチなどに使われます。
  • beforeRouteLeave(to, from, next): 現在のルートから別のルートへ移動しようとする直前に呼び出されます。例えば、ユーザーが編集中のフォームから離れようとしたときに、「変更内容を保存せずに移動しますか?」といった確認ダイアログを表示するのに使われます。このガードは this にアクセスできます。next(false) を呼び出すことで遷移を中止できます。

コンポーネント内ガードの例:

“`vue

“`

ナビゲーションガードの実行順序:

完全なナビゲーションフローが発生した場合、ガードは以下の順序で呼び出されます。

  1. 遷移前のルートの beforeRouteLeave ガード
  2. グローバル beforeEach ガード
  3. 再利用されるコンポーネントの beforeRouteUpdate ガード (あれば)
  4. ルート設定の beforeEnter ガード
  5. 非同期ルートコンポーネントの解決
  6. 遷移先のルートコンポーネントの beforeRouteEnter ガード
  7. グローバル beforeResolve ガード
  8. ナビゲーション完了
  9. グローバル afterEach フック

この実行順序を理解しておくと、どのガードでどのような処理を行うべきか判断しやすくなります。例えば、認証チェックは最も早い段階の beforeEach で行うのが効率的です。データフェッチは、コンポーネントが表示される前に完了させたいなら beforeRouteEnter で、またはパラメータが変わるたびに再実行したいなら beforeRouteUpdate やコンポーネントの watch で行うのが一般的です。

11. データフェッチ

SPAにおけるルーティングでは、特定のルートにアクセスした際に、そのルートで表示するのに必要なデータを取得する必要があります。データフェッチのタイミングはいくつか考えられます。

11.1 ナビゲーションの前にデータを取得する方法

これは、ナビゲーションガード (beforeRouteEnter, beforeRouteUpdate, beforeEach, beforeEnter) 内でデータフェッチを行い、フェッチが完了してから next() を呼び出す方法です。

  • 利点: データが完全に取得されるまで画面の遷移がブロックされます。これにより、遷移先のコンポーネントは描画された時点で必要なデータが全て揃っていることが保証されます。ローディングスピナーなどを表示することで、ユーザーに待機中であることを伝えることができます。
  • 欠点: データフェッチに時間がかかると、画面遷移が遅く感じられる可能性があります。空の画面がすぐに表示されるのではなく、遷移元の画面がデータフェッチ完了までそのまま表示されることになります。

beforeRouteEnter ガードでのデータフェッチ例:

“`vue

“`

11.2 ナビゲーション後にデータを取得する方法

これは、コンポーネントがマウントされた後(mounted フックや onMounted フック)、またはパラメータ変更を監視して(watchwatchEffectbeforeRouteUpdate)データフェッチを行う方法です。

  • 利点: 画面遷移はすぐに完了し、空のテンプレートや既存のデータが表示されます。その後、非同期でデータがロードされ、ロード完了後に表示が更新されます。これにより、ユーザーは「ページが固まっている」と感じにくくなります。
  • 欠点: データがロードされるまでコンテンツが表示されない「ちらつき」が発生する可能性があります。ローディング状態やエラー状態を適切にUIで示す必要があります。

mounted フックでのデータフェッチ例:

“`vue

“`

どちらの方法を選択するかは、アプリケーションの要件やユーザー体験の目標によります。データのロードに時間がかかることが予想される場合や、素早い画面表示を優先したい場合は、ナビゲーション後のフェッチが良いでしょう。データが必須で、データなしではコンポーネントが正しく表示できない場合は、ナビゲーション前のフェッチが適しています。両方を組み合わせることも可能です(例えば、ナビゲーションガードで簡単なチェックやリダイレクトを行い、コンポーネント内でデータフェッチを行うなど)。

Composition API を使う場合、watchEffect を使うと onMountedwatch のロジックをシンプルにまとめることができます。

“`javascript
// using watchEffect in setup
import { ref, watchEffect } from ‘vue’;
// … api service …

export default {
// … props …
setup(props) {
const post = ref(null);
const isLoading = ref(true);
const error = ref(null);

watchEffect(async () => {
  const postId = props.postId; // props.postId に依存
  if (postId) {
    console.log(`watchEffect: Fetching post ${postId}`);
    post.value = null;
    error.value = null;
    isLoading.value = true;
    try {
      post.value = await api.fetchPost(postId);
    } catch (err) {
      error.value = err;
    } finally {
      isLoading.value = false;
    }
  } else {
     // postId が undefined などになった場合
     post.value = null;
     error.value = null;
     isLoading.value = false;
  }
});

return {
  post,
  isLoading,
  error,
};

},
};
``watchEffectは、依存するリアクティブな値が変更されるたびに効果を再実行します。初期実行も行われるため、onMountedwatch` を組み合わせたような動作を簡単に実現できます。特にルートパラメータをpropsで受け取っている場合に便利です。

12. スクロールの挙動

SPAでは、ページ遷移してもブラウザのスクロール位置が自動的にリセットされません。あるページの下部から別のページに遷移しても、遷移先のページが下部から表示されてしまうことがあります。

Vue Routerは、ルート遷移時のスクロール挙動をカスタマイズするための scrollBehavior オプションを提供しています。

12.1 scrollBehavior オプション

ルーターインスタンスを作成する際に、scrollBehavior 関数を定義して指定します。

“`javascript
// src/router/index.js

import { createRouter, createWebHistory } from ‘vue-router’;

// … routes 定義 …

const router = createRouter({
history: createWebHistory(),
routes,
// ここに scrollBehavior 関数を定義
scrollBehavior(to, from, savedPosition) {
// savedPosition は、ブラウザの戻る/進むボタンで遷移したときに保存される位置
if (savedPosition) {
return savedPosition; // 保存された位置があればそこに戻る
} else if (to.hash) {
// URLにハッシュ (#section) が含まれている場合、指定された要素にスクロール
return {
el: to.hash, // CSSセレクタを指定
behavior: ‘smooth’, // オプション: スムーズスクロール
};
} else {
// それ以外の場合、ページの先頭にスクロール
return { top: 0, left: 0 };
// return { x: 0, y: 0 }; // 同じ意味
}
},
});

export default router;
“`

scrollBehavior 関数は、ナビゲーションが発生するたびに呼び出されます。引数として以下の3つを受け取ります。

  • to: 遷移先のルートオブジェクト
  • from: 遷移元のルートオブジェクト
  • savedPosition: ブラウザの戻る/進むボタンによる遷移の場合にのみ存在する、保存されていたスクロール位置情報 ({ top: number, left: number } または { x: number, y: number })

関数は、スクロール位置を定義するオブジェクトを返すべきです。返せる値は以下の形式です。

  • { top: number, left: number } または { x: number, y: number }: 指定した座標にスクロールします。
  • { el: string, behavior: 'smooth' | 'auto' }: 指定したCSSセレクタに一致する要素にスクロールします。オプションでスクロール挙動を指定できます。
  • false: スクロール位置を保持します。
  • null または undefined: デフォルトのスクロール挙動(ブラウザの実装による)になります。

12.2 非同期処理との連携

もしスクロール先の要素が非同期でロードされるコンテンツ内にあり、スクロール処理が要素の描画完了を待つ必要がある場合、scrollBehavior 関数は Promise を返すことができます。

javascript
scrollBehavior(to, from, savedPosition) {
if (savedPosition) {
return savedPosition;
} else if (to.hash) {
return new Promise((resolve, reject) => {
// 要素がレンダリングされるのを待つ(例: setTimeoutで少し待つ、またはmutation observerを使うなど)
setTimeout(() => {
const el = document.querySelector(to.hash);
if (el) {
resolve({ el, behavior: 'smooth' });
} else {
// 要素が見つからなければページの先頭へ
resolve({ top: 0 });
}
}, 500); // 例として500ms待つ
});
} else {
return { top: 0 };
}
}

通常は nextTick を使ってDOMが更新されるのを待つか、簡単な場合は setTimeout で少し待つことが多いです。より複雑なケースでは Intersection Observer や Mutation Observer を利用することも考えられます。

scrollBehavior を適切に設定することで、SPAでもユーザーフレンドリーなスクロール挙動を実現できます。

13. 高度な設定とAPI

これまでに学んだ基本的な機能に加えて、Vue Routerにはさらに多くのオプションやAPIがあります。

13.1 モードについて深掘り (History API vs Hash)

前述の通り、createWebHistory() (History API) はクリーンなURLを提供しますが、サーバ設定が必要です。createWebHashHistory() (Hashモード) はサーバ設定不要ですが、URLに # が含まれます。

  • History API (createWebHistory):

    • https://example.com/users/123
    • 利点: クリーンなURL, より自然なナビゲーション、SEO上有利な可能性 (ただしSPAのSEOは複雑)
    • 欠点: サーバ設定必須 (どのパスへのリクエストも index.html を返すようにする必要がある)
    • ローカル開発サーバ (Vite, webpack-dev-serverなど) は通常自動で対応
    • 本番環境での設定例 (Nginx):
      nginx
      location / {
      try_files $uri $uri/ /index.html;
      }
    • 本番環境での設定例 (Apache):
      .htaccess ファイルに以下を記述
      apache
      <Ifaughey -f %{REQUEST_FILENAME}>
      RewriteCond %{REQUEST_FILENAME} !-f
      RewriteCond %{REQUEST_FILENAME} !-d
      RewriteRule ^.*$ /index.html [L]
      </Ifaughey>
  • Hashモード (createWebHashHistory):

    • https://example.com/#/users/123
    • 利点: サーバ設定不要、静的なファイルサーバでも動作
    • 欠点: URLに # が含まれる、URLが少し不格好に感じられる場合がある

プロダクション環境へのデプロイを考慮すると、通常は History API を選択し、対応するサーバ設定を行うのがモダンなSPA開発の標準です。

13.2 ベースURL (base オプション)

アプリケーション全体がウェブサイトのルート (/) ではなく、サブディレクトリ(例: https://example.com/my-app/)にデプロイされる場合、ルーターにベースURLを指定する必要があります。これは createWebHistory 関数の引数として渡します。

javascript
// アプリケーションが /my-app/ というパス以下にデプロイされる場合
const router = createRouter({
history: createWebHistory('/my-app/'), // ベースURLを指定
routes,
});

Vue CLIやViteなどのビルドツールを使っている場合、環境変数(例: process.env.BASE_URL や Vite の import.meta.env.BASE_URL)を使ってビルド時に自動的に設定されることが多いです。

13.3 ルーターオプションの詳細

createRouter に渡す設定オブジェクトには、他にもいくつかのオプションがあります。

  • linkActiveClass: 現在のマッチしているルートの親ルートまでの <router-link> に付与されるCSSクラス名(デフォルト: router-link-active)。
  • linkExactActiveClass: 現在のルートと完全に一致する <router-link> に付与されるCSSクラス名(デフォルト: router-link-exact-active)。通常はこちらを使って、完全に一致するリンクだけをハイライトします。
  • routes: ルート定義の配列(必須)。
  • history: 履歴モード(必須)。

13.4 ルーターインスタンスへのアクセス (this.$router, $route)

Vueコンポーネント内でルーターインスタンスや現在のルート情報にアクセスするには、以下の方法があります。

  • Options API:
    • ルーターインスタンス: this.$router (ナビゲーションメソッド push, replace などにアクセス)
    • 現在のルート情報: this.$route (パス、パラメータ、クエリ、ハッシュ、メタフィールドなどにアクセス)
  • Composition API (setup 関数内):
    • ルーターインスタンス: const router = useRouter();
    • 現在のルート情報: const route = useRoute();
      useRouter および useRoutevue-router からインポートします。

“`vue

``$routeおよびuseRoute()から取得するrouteオブジェクトはリアクティブです。URLが変更されると自動的に更新され、それを使用しているテンプレートや算出プロパティなどが再計算されます。$routerおよびuseRouter()から取得するrouter` インスタンスはリアクティブではありません(メソッド群なので)。

14. よくある問題とデバッグ

14.1 404ページの作成 (catch-all ルート)

どのルート定義にもマッチしなかった場合に表示する「404 Not Found」ページを作成するには、ルート定義の最後に「catch-all」ルートを追加します。パスは、全てのパスにマッチするようなワイルドカード (.*) を使用します。

Vue Router v4 以降では、catch-all ルートの書き方が変わりました。/:pathMatch(.*)* のように、パラメータ名を指定し、パス全体にマッチさせるための正規表現 (.*) と、スラッシュを含む複数セグメントに対応するための * 修飾子を組み合わせます。

“`javascript
// src/router/index.js

import NotFoundView from ‘../views/NotFoundView.vue’;

const routes = [
// … 他の全てのルート定義 …

// catch-all ルートは必ず最後に定義する
{
// どのルートにもマッチしなかった場合、このルートがマッチする
// : 0個以上のセグメントにマッチ (必須)
// ?: 0個または1個のセグメントにマッチ
// +: 1個以上のセグメントにマッチ
// (.
): 任意の文字の0回以上の繰り返しにマッチ(正規表現グループ)
// : その前の要素(ここではグループ(.))が0回以上繰り返されることを示す
path: ‘/:pathMatch(.)‘, // Vue Router v4 の推奨される書き方
name: ‘NotFound’,
component: NotFoundView,
},
// v3 の書き方 (非推奨、v4では使えない)
// {
// path: ‘‘,
// redirect: ‘/404’
// }
];
``:pathMatch(.
)とすることで、例えば/non-existent/pageというパスにアクセスした場合、:pathMatchパラメータには[“non-existent”, “page”]という配列が入ります。もしパスパラメータとしてパス全体を文字列で取得したい場合は、正規表現を少し調整する必要があります。例えば/:catchAll(.)のようにすると、/non-existent/pageに対してcatchAll“non-existent/page”という文字列が入ります。しかし、公式ドキュメントでは:pathMatch(.)` が推奨されています。

NotFoundView.vue は通常のVueコンポーネントとして作成します。

14.2 ルーターが動作しない場合のチェックポイント

  • インストールしましたか? npm install vue-router@next または yarn add vue-router@next を実行しましたか?
  • アプリケーションに組み込みましたか? main.js (または main.ts) で app.use(router) を呼び出していますか?
  • ルーターインスタンスを作成しましたか? createRouter を呼び出し、historyroutes オプションを正しく設定していますか?
  • <router-view> を配置しましたか? アプリケーションのメインレイアウト (通常 App.vue) に <router-view> がありますか?ネストされたルートを使っている場合は、親コンポーネント内に <router-view> がありますか?
  • <router-link> を使っていますか? ページ遷移には <router-link> または router.push() などのプログラムによるナビゲーションを使っていますか?通常の <a> タグではSPAのルーティングは機能しません(ページ全体のリロードになります)。
  • Historyモードの場合、サーバ設定はできていますか? createWebHistory() を使っている場合、どのパスへのアクセスでも index.html を返すようにWebサーバやホスティングサービスが設定されていますか?ローカル開発サーバ(Vite, webpack dev serverなど)を使っている場合は通常自動で対応されますが、本番環境では手動設定が必要です。
  • パスの定義は正しいですか? パスのスペルミス、大文字小文字の違い(一部環境では区別される)、末尾のスラッシュの有無などに注意してください。ネストされたルートの場合、子ルートのパスには先頭に / をつけません。
  • コンポーネントは正しくインポートされていますか? ルート定義で指定したコンポーネントが正しくインポートされていますか?非同期コンポーネントを使用している場合は、ロードに失敗していないか確認してください。

14.3 開発ツール (vue-devtools) の利用

Vue.js開発者ツール (vue-devtools) は、Vue Routerのデバッグに非常に役立ちます。ブラウザの拡張機能としてインストールすると、Vueアプリケーションのコンポーネントツリーや状態を確認できるだけでなく、「Router」タブが表示されます。

「Router」タブでは、現在のルート情報(パス、名前、パラメータ、クエリ、メタフィールドなど)や、定義されている全てのルート一覧、ナビゲーションの履歴などを確認できます。これにより、意図したルートにマッチしているか、パラメータが正しく渡されているかなどを視覚的に確認できます。

15. まとめ

この記事では、Vue Routerの基本から応用まで、幅広く解説しました。

  • Vue Routerは、SPAでURLとコンポーネントのマッピングを管理し、ブラウザ履歴に対応するための公式ライブラリです。
  • createRouter でルーターインスタンスを作成し、history モード(History APIまたはHashモード)と routes 定義を設定します。
  • App.vue のようなメインレイアウトに <router-view> を配置し、現在のルートコンポーネントを表示させます。
  • ページ遷移のためのリンクには <router-link> を使用します。
  • :paramName を使って動的なパスパラメータを定義し、$route.params または推奨される props: true オプションでコンポーネントに渡します。
  • children プロパティと親コンポーネント内の <router-view> を使ってネストされたルーティングを実現します。
  • name プロパティでルートに名前をつけ、{ name: '...' } オブジェクトを使ってナビゲーションコードのメンテナンス性を向上させます。
  • components プロパティと名前付き <router-view> を使って、複数のビューを持つレイアウトを実現します。
  • router.push(), router.replace(), router.go() などのメソッドを使って、プログラムによるナビゲーションを実行します。
  • redirectalias オプションで、リダイレクトや複数のパスを同じコンポーネントにマッピングする設定を行います。
  • beforeEach, beforeEnter, beforeRouteEnter, beforeRouteUpdate, beforeRouteLeave, afterEach といったナビゲーションガードを使って、ルート遷移の各段階で処理を実行できます。
  • データフェッチは、ナビゲーションガード内(遷移前)またはコンポーネントのライフサイクルフック/リアクティブ監視(遷移後)で行うことができます。
  • scrollBehavior オプションで、ルート遷移時のスクロール位置を制御できます。
  • :pathMatch(.*)* を使って404ページを実装できます。

Vue Routerは非常に柔軟で強力なルーティングライブラリです。これらの基本をマスターすれば、どんな規模のSPAでも効率的にルーティングを管理できるようになるでしょう。

次のステップ:

  • 公式ドキュメントを読む: Vue Routerの公式ドキュメントは非常に詳細で正確です。この記事で紹介しきれなかった高度な機能(遷移効果、データフェッチのより高度なパターンなど)や詳細なAPIについて学ぶことができます。
  • 実際にコードを書いてみる: 小さなプロジェクトでも良いので、この記事で学んだことを実際に手を動かして実装してみましょう。
  • 複雑なレイアウトやガードの実装に挑戦する: 複数の名前付きビューを使った複雑なレイアウトや、認証・権限管理を含むナビゲーションガードを実装してみましょう。

これで、Vue Routerの基本的な使い方に関する詳細な解説は終わりです。あなたのVue.js開発に役立てば幸いです!


コメントする

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

上部へスクロール