はじめに
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>
のブロックで構成されている。 ↩