はじめに
Vue.js には URL の移動を伴う画面遷移の手段として ルーティング という仕組みが用意されている。
本記事では簡単な例を元に以下の 2点について見ていく。
前提
- Vue CLI でプロジェクトを作成していること
- 単一ファイルコンポーネントであること( 1 )
- 動作確認は
$ npm run serveで起動した環境で行なっている
環境
| Version | 備考 | |
|---|---|---|
| Vue | 2.6.11 | 公式はこちら |
| Vue CLI | 4.1.1 | 公式はこちら |
| Vue Router | 3.0.7 | Vue.js の公式ルータ, 公式はこちら |
| Buefy | 0.9.2 | Vue.js 用の UI コンポーネント, MIT ライセンス, 公式はこちら |
事前準備
vue-router の追加
package.json に vue-router を追加して npm install でモジュールを追加する。
今回の記事で扱ったバージョンは 3.0.7。
// 省略
{
"dependencies": {
"vue-router": "3.0.7", // コレを追加
}
}
// 省略
$ npm install
added 1 package from 1 contributor and audited 1299 packages in 6.541s
基本
この項目で扱う内容は次の 3点。
- ルーティングで扱いたいページの追加
- ルーティングを管理するファイルの追加
- Vue.js 上でルーティングを扱うための 2つ のファイル修正
で、表にまとめると以下のようになる。
| ファイル | 新規 / 修正 | 備考 |
|---|---|---|
| *.vue | 新規 | ルーティングで扱いたいページ |
| router.js | 新規 | ルーティングを管理する |
| main.js | 修正 | ルーティングを扱うために修正 |
| App.vue | 修正 | 同上 |
では上から順に見ていく。
ページ( *.vue )の追加
ルーティングで扱いたいページを実装する。
とは言っても、ここで扱う内容に特別なものはない。単純に 単一コンポーネントでページを実装しただけである。
<template>
<div :class="$style.parent">
<div :class="$style.child">
<h1>Routing Test Page</h1>
</div>
</div>
</template>
<script>
export default {
name: 'Routing'
}
</script>
// スタイルは割愛
router.js ファイルを新規作成
こちらはルーティングを管理するための JavaScript ファイル。
import Vue from 'vue'
import Router from 'vue-router'
import Home from './views/Home.vue'
import Routing from './views/Routing.vue'
//
// 他のコンポーネントは省略
//
Vue.use(Router)
export default new Router({
// デフォルトの挙動では URL に `#` が含まれる.
// URL から hash を取り除くには `mode:history` を指定する
mode: 'history',
base: process.env.BASE_URL,
routes: [
{
path: '/',
name: 'home',
component: Home
},
//
// 省略
//
{
path: '/routing',
name: 'routing',
component: Routing
}
]
})
短いコードではあるがポイントがいくつかある。以下、順に見ていく。
-
vue-routerのimport-
事前準備 で導入した
vue-routerをimportしている - ここは特筆すべきことはなく、単純に
vue-routerを使うための宣言である
-
事前準備 で導入した
-
vue-routerの登録-
importしたvue-routerを Vue で使えるようにVue.use()で指定する - これにより Vue アプリ上で
vue-routerを使ったルーティングが可能になる
-
-
vue-routerのインスタンス生成とexport-
vue-routerのインスタンスを生成し、それをexportしている - これにより 各コンポーネントでは 本 JS ファイル(
router.js) をimportすることなくthis.$routerで参照 することができる
-
-
ルーティングの設定
-
routesプロパティを配列で定義し、その中に以下を設定することで path に応じたコンポーネントが呼び出される - ここの内容でルーティングのためのルールを設定することになる。 公式の Vue Router を充分に理解しておきたい
-
| 項目 | 説明 | 備考 |
|---|---|---|
| path | URL の path |
<router-link> で指定する文字列を間違えないように注意すること |
| name |
<router-link> や router.push で指定する名前 |
両者を使わないのであれば設定不要。だが設定しておいた方が良いと思う |
| component | 呼び出されるコンポーネント |
<router-view /> が配置された箇所でレンダリングされる |
main.js の修正
このファイルの修正は単純で、 アプリケーション上でルーティングを行うために、前項で作成した
-
router.jsのimport - Vue インスタンス生成時に
router.jsのインスタンスのセット
の 2点 を行っている。
import Vue from 'vue'
import App from './App.vue'
// ルーティングのために追加
import router from './router'
Vue.config.productionTip = false
new Vue({
router, // ルーティングのために追加
render: h => h(App),
}).$mount('#app')
App.vue の修正
こちらは前項で挙げた main.js の
new Vue({
router, // ルーティングのために追加
render: h => h(App),
}).$mount('#app')
の部分で読み込まれていて、アプリケーションの起点となるファイルである。
この App.vue では、テンプレート部分で router.js で定義したルーティングルールとの紐付けを行っている。
<template>
<div id="app">
<div
id="nav"
class="tab-area-base">
<ul class="tab-menu-base">
<!-- `router.js` で定義したルーティングルールとの紐付けを行っている -->
<li><router-link to="/">Home</router-link></li>
<!-- *** -->
<!-- 省略 -->
<!-- *** -->
<li><router-link to="/routing">Rounting Test</router-link></li>
</ul>
</div>
<router-view />
</div>
</template>
// ▼ ここから削除 ( ルーティングによって不要となるため )
//<script>
//import HelloWorld from './components/HelloWorld.vue'
//
//export default {
// name: 'App',
// components: {
// HelloWorld
// }
//}
//</script>
// ▲ ここまで削除
// スタイルは割愛
このファイルもいくつかポイントがあるので順に見ていく。
-
<template>部分-
<router-link>- 遷移先の設定を行っている
- ここで
to=で設定しているのが router.js で設定 したパスとなる - 指定する文字列を間違うと リンクをクリックしても遷移しない うえに、コンソール上にエラーも出ない ため、意外と不具合の原因を探しづらいので注意されたい
-
<router-view />- ここの部分に
<router-link>からrouter.jsを経由して呼び出されたコンポーネントの内容が描画される - これが無いと コンポーネントを呼び出しているの描画されない ということになるので注意
- ここの部分に
-
-
<script>部分- コード中のコメントにもあるとおり、ルーティングを使うことで本ファイルでのコンポーネントの呼び出しは不要になった
動作確認
ここまでルーティングの基本について見てきた。
では実際にどう動くのかをキャプチャをもとに見ていく。
ルーティング前
App.vue の修正前 のコードにあるように、HelloWorld.vue がそのまま表示されている。
ルーティング後
-
初期表示 or Home タブを選択
ルーティングの実装後。
画面にはタブが表示され、Homeタブの URL であるhttp://localhost:8080には初期画面として ルーティング前 と同じHelloWorld.vueの画面が表示されている。

-
Routing Test タブを選択
Routing Testタブの URL であるhttp://localhost:8080/routingでは、新たに実装したページであるRouting.vueの画面が表示されている。

以上、ルーティングの基礎について見てきたが、決められたルールに沿うことで、少ない手間で URL を指定したページ遷移が実現できることがわかった。
次の項目では ルーティング時にパラメータの受け渡しを行う 方法について見ていく。
進んだ使い方
vue-router を使ったルーティングでは 任意の値をパラメータとして受け渡す ために
- URL のパターンマッチングによるページ遷移
-
router.pushを使ったページ遷移
といった方法が用意されている。
以下、それぞれの方法について見ていく。
パターンマッチングによるページ遷移
URL のパターンマッチングによってパラメータの受け渡しを行うケース。ここで挙げる例は以下のとおり。
- ユーザ情報の詳細を持つコンポーネント
UserDetail.vueがある - そのコンポーネントに対してユーザIDを URL で指定する
- 指定したユーザ情報の詳細を表示するページに遷移する
基本 の項目でルーティングのための準備はできているので、本項では router.js への追記とユーザ情報の詳細を持つコンポーネント UserDetail.vue について扱う。
router.js への追記
パターンマッチングでのページ遷移の実現にあたり、まずは router.js で URL でのパラメータの受け渡し のための設定を記述する。
具体的には以下のとおり。
import Router from 'vue-router'
import UserDetail from './views/UserDetail.vue'
Vue.use(Router)
export default new Router({
{
path: '/users/:id',
name: 'user-detail',
component: UserDetail
}
]
})
ポイントは path: '/users/:id' の部分。 path 内の URL に : を使用する ことでパターンマッチングを実現する。
コンポーネントでは $route.params から、ここで指定したパラメータ名と 同じ名前でアクセス することで値を取得できる。
UserDetail.vue
UserDetail.vue は router.js で URL によるパターンマッチングでの遷移を行う際に指定されたコンポーネント。
前述の説明のとおり、下記のコードでは $route.params.id とすることで '/users/:id' で指定した id の値を取得 している。
<template>
<div :class="$style.component">
<h1>This page is user detail.</h1>
<div
:class="$style.userinfo">
<table>
<th :class="$style.item">
ITEM
</th>
<th :class="$style.value">
VALUE
</th>
<!-- users のリストにアクセスする際、インデックスは 0 からなので受け取った id の値から `-1` する -->
<tr
v-for="(value, name) in users[$route.params.id - 1]"
:key="name">
<td :class="$style.item">
{{ name }}
</td>
<td :class="$style.value">
{{ value }}
</td>
</tr>
</table>
</div>
</div>
</template>
<script>
export default {
name: 'UserDetail',
data: function () {
// 返却するオブジェクト users は本コンポーネントで表示するユーザ情報
// 本来ならば DB 等で保持するのだが、今回は記事用のサンプルコードということでリストで持たせている
return {
users: [
{
id: 1,
name: 'hogehoge',
live: 'Japan Tokyo',
phone: 'NNN-XXXX-HHHH',
gender: 'male',
mail: 'hogehoge@mail.com'
},
{
id: 2,
name: 'barbar',
live: 'Japan Kanagawa',
phone: 'NNN-XXXX-BBBB',
gender: 'male',
mail: 'barbar@mail.com'
},
{
id: 3,
name: 'piypiyo',
live: 'Japan Kanagawa',
phone: 'NNN-XXXX-PPPP',
gender: 'female',
mail: 'piypiyo@mail.com'
},
{
id: 4,
name: 'fugafuga',
live: 'Japan Chiba',
phone: 'NNN-XXXX-FFFF',
gender: 'male',
mail: 'fugafuga@mail.com'
},
{
id: 5,
name: 'varvar',
live: 'Japan Saitama',
phone: 'NNN-XXXX-VVVV',
gender: 'female',
mail: 'varvar@mail.com'
}
],
}
}
}
</script>
// スタイルは割愛
動作確認
動作確認の結果が以下のキャプチャ。
URL に
-
http://localhost:8080/users/1を指定することでid: 1のユーザ情報詳細 -
http://localhost:8080/users/4を指定することでid: 4のユーザ情報詳細
が、ぞれぞれ表示されることが確認できた。
ボタンアクションによるページ遷移
前掲の パターンマッチング で URL上でパラメータがセットされたケース の例について触れた。
ここではボタンアクションによる パラメータの受け渡しを伴うページ遷移 について扱う。
ここで挙げる例は以下のとおり。
- ユーザのリストを表示するコンポーネント
UserList.vueと、その親コンポーネントUsers.vueがある - コンポーネント
UserList.vueでテーブルから任意のレコードを選択してShow more seleted...ボタンをクリックすることで - 指定したユーザ情報の詳細を表示するコンポーネント
UserDetail.vueを呼び出す( 遷移する )
コードを見る前に
上記 3 つのコンポーネントの概要を表にすると以下のとおり。
| コンポーネント | 概要 | 子コンポーネント | 備考 |
|---|---|---|---|
| Users.vue | User 情報を持つ | UserList.vue | |
| UserLive.vue | User 情報をテーブルで表示する | なし | |
| UserDetails | 指定された User 情報の詳細を表示する | なし | 前項 で扱っているのでここではコードを扱わない |
このうち Users.vue と UserDetail.vue は同じデータオブジェクトをそれぞれのコンポーネント内で定義している。
本来ならばこれらのデータは DB なり localStorage で持つなり、なんらかの手段でデータの共有化を図るべきなのだけれども、今回は ルーティングが主題 であるためデータの持ち方については考慮外とした。
Users.vue
Users.vue はユーザの一覧をオブジェクトとして持ち、画面描画時に子コンポーネントである UserList.vue にユーザ情報を渡すだけの単純なもの。
- コンポーネントの親子関係
- 親コンポーネント → 子コンポーネントへのデータ授受
についても少し見てみたいと思い試してみた。
( コンポーネント間のデータのやりとりについては、別途記事を設けて見ていきたい )
<template>
<div :class="$style.component">
<UserList :properties="properties" />
</div>
</template>
<script>
// @ を指定することで `/src` の代替となる
import UserList from '@/components/UserList.vue'
export default {
name: 'Users',
components: {
UserList
},
data: function () {
// ここで返却するデータは子コンポーネント `UserList.vue` で表示するユーザ情報
// 本来ならば DB 等で保持するのだが、今回は記事用のサンプルコードということでリストで持たせている
return {
properties: {
users: [
{
id: 1,
name: 'hogehoge',
live: 'Japan Tokyo',
phone: 'NNN-XXXX-HHHH',
gender: 'male',
mail: 'hogehoge@mail.com'
},
{
id: 2,
name: 'barbar',
live: 'Japan Kanagawa',
phone: 'NNN-XXXX-BBBB',
gender: 'male',
mail: 'barbar@mail.com'
},
{
id: 3,
name: 'piypiyo',
live: 'Japan Kanagawa',
phone: 'NNN-XXXX-PPPP',
gender: 'female',
mail: 'piypiyo@mail.com'
},
{
id: 4,
name: 'fugafuga',
live: 'Japan Chiba',
phone: 'NNN-XXXX-FFFF',
gender: 'male',
mail: 'fugafuga@mail.com'
},
{
id: 5,
name: 'varvar',
live: 'Japan Saitama',
phone: 'NNN-XXXX-VVVV',
gender: 'female',
mail: 'varvar@mail.com'
}
]
}
}
}
}
</script>
// スタイルは割愛
UserList.vue
UserList.vue は親コンポーネントである Users.vue から受け取ったデータをテーブルで表示するコンポーネント。
テーブルの実現には Buefy の Table を使用している。
<template>
<div>
<h1>This page is user list.</h1>
<div :class="$style.userlist">
<!-- Buefy のテーブルを使って実現 -->
<!-- https://buefy.org/documentation/table/ -->
<b-table
:data="properties.users"
:columns="columns"
:striped="true"
:hoverable="true"
:selected.sync="selected" />
</div>
<div :class="$style.showmore">
<b-button
type="is-info"
@click="showMoreInformation">
Show more selected...
</b-button>
</div>
</div>
</template>
<script>
export default {
name: 'UserList',
props: {
properties: {
type: Object,
'default': () => { return null },
}
},
data: function() {
return {
// `selected`, `columns` は Buefy のテーブルを使用する際に必要なパラメータ
// https://buefy.org/documentation/table/
selected: null,
columns: [
{
field: 'id',
label: 'ID',
width: '50',
numeric: true
},
{
field: 'name',
label: 'NAME',
width: '400',
centered: true
},
{
field: 'mail',
label: 'MAIL',
width: '400',
centered: true
},
]
}
},
methods: {
showMoreInformation: function() {
// アロー関数で定義すると `this` で `selected` が参照できない。
// 詳細は https://qiita.com/_Keitaro_/items/d48733a19c10889e2365 を参照のこと。
if (!this.selected) {
alert('No data selected...')
return false
}
const selected = this.selected
this.$router.push({
name: 'user-detail',
params: { id: selected['id'] }
})
}
}
}
</script>
// スタイルは割愛
本コンポーネントのポイントはボタンクリック時に実行されるメソッドである showMoreInformation 。
レコードを選択した状態で showMoreInformation が実行されると UserDetail.vue コンポーネントが表示され、選択されたユーザ情報の詳細が表示される。
その動きを実現しているのが下記の部分。
const selected = this.selected
this.$router.push({
name: 'user-detail',
params: { id: selected['id'] }
})
this.$router.push の引数に name と params プロパティをセットすることでルーティングを実現させている。
ここで name と params.id は パターンマッチング の router.js で設定した
{
path: '/users/:id',
name: 'user-detail',
component: UserDetail
}
の部分とリンクしている。
それぞれの相関を表にすると次のとおり。
| UserList.vue のコード | router.js のコード | |
|---|---|---|
| name | name: 'user-detail' |
name: 'user-detail' |
| id | params: { id: selected['id'] } |
path: '/users/:id' |
こうした name プロパティを利用したルーティングを 名前付きルート というらしい。
動作確認
動作確認の結果が以下のキャプチャ。
-
User Listタブで表示されたテーブルからid: 3のレコードを選択してShow more selected...ボタンをクリック -
UserDetailタブに遷移してid: 3のユーザ情報詳細が表示される
ことが確認できた。
まとめ
基本
- ルーティングには
vue-routerを使うと簡単に実現できる - ルーティングを管理するために
router.jsを実装してmain.jsでimportすることで利用する -
App.vueでは以下を行ってうことで画面遷移を実現する-
router-linkで遷移先の指定 -
router-viewで遷移先のページの表示
-
進んだ使い方
- ルーティング時に任意の値をパラメータとして渡すことができる
- そのための手段として以下を用いる
- URL パラメータとして指定する
-
router.push時にパラメータとして指定する
-
router.push時に遷移先としてnameを指定することを 名前付きルート という
ソースコード
今回の記事で動作確認に使用したコードは下記にアップしております。
ご参考まで。
( 以下は ブランチのリンクですが、 master にもマージ済みです )
( master は Vue v3.x 系に移行しました. 本記事の内容は下記ブランチでご確認ください )
参考
公式
-
Vue.js のコンポーネントを単独のファイルとして作成する機能
拡張子「.vue」のファイルのことで<template>,<script>,<style>のブロックで構成されている。 ↩




