LoginSignup
68
87

More than 1 year has passed since last update.

[Vue.js] ルーティング による画面遷移

Last updated at Posted at 2020-11-13

はじめに

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

package.json
// 省略
{
  "dependencies": {
    "vue-router": "3.0.7",  // コレを追加
  }
}
// 省略
vue-routerを追加
$ 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 ファイル。

router.js
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 
    }
  ]
})

短いコードではあるがポイントがいくつかある。以下、順に見ていく。

  1. vue-routerimport

    • 事前準備 で導入した vue-routerimport している
    • ここは特筆すべきことはなく、単純に vue-router を使うための宣言である
  2. vue-router の登録

    • import した vue-router を Vue で使えるように Vue.use() で指定する
    • これにより Vue アプリ上で vue-router を使ったルーティングが可能になる
  3. vue-router のインスタンス生成と export

    • vue-router のインスタンスを生成し、それを export している
    • これにより 各コンポーネントでは 本 JS ファイル(router.js ) を import することなく this.$router で参照 することができる
  4. ルーティングの設定

    • routes プロパティを配列で定義し、その中に以下を設定することで path に応じたコンポーネントが呼び出される
    • ここの内容でルーティングのためのルールを設定することになる。 公式の Vue Router を充分に理解しておきたい
項目 説明 備考
path URL の path <router-link> で指定する文字列を間違えないように注意すること
name <router-link>router.push で指定する名前 両者を使わないのであれば設定不要。だが設定しておいた方が良いと思う
component 呼び出されるコンポーネント <router-view /> が配置された箇所でレンダリングされる

main.js の修正

このファイルの修正は単純で、 アプリケーション上でルーティングを行うために、前項で作成した

  • router.jsimport
  • Vue インスタンス生成時に router.js のインスタンスのセット

の 2点 を行っている。

main.js
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

main.js
new Vue({
  router, // ルーティングのために追加
  render: h => h(App),
}).$mount('#app')

の部分で読み込まれていて、アプリケーションの起点となるファイルである。
この App.vue では、テンプレート部分で router.js で定義したルーティングルールとの紐付けを行っている。

App.vue
<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>
// ▲ ここまで削除

// スタイルは割愛

このファイルもいくつかポイントがあるので順に見ていく。

  1. <template> 部分
    • <router-link>
      • 遷移先の設定を行っている
      • ここで to= で設定しているのが router.js で設定 したパスとなる
      • 指定する文字列を間違うと リンクをクリックしても遷移しない うえに、コンソール上にエラーも出ない ため、意外と不具合の原因を探しづらいので注意されたい
    • <router-view />
      • ここの部分に <router-link> から router.js を経由して呼び出されたコンポーネントの内容が描画される
      • これが無いと コンポーネントを呼び出しているの描画されない ということになるので注意
  2. <script> 部分
    • コード中のコメントにもあるとおり、ルーティングを使うことで本ファイルでのコンポーネントの呼び出しは不要になった

動作確認

ここまでルーティングの基本について見てきた。
では実際にどう動くのかをキャプチャをもとに見ていく。

ルーティング前

App.vue の修正前 のコードにあるように、HelloWorld.vue がそのまま表示されている。

スクリーンショット 2020-09-13 1.13.51.png

ルーティング後

  1. 初期表示 or Home タブを選択
    ルーティングの実装後。
    画面にはタブが表示され、 Home タブの URL である http://localhost:8080 には初期画面として ルーティング前 と同じ HelloWorld.vue の画面が表示されている。
    スクリーンショット 2020-09-21 20.52.17.png

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

以上、ルーティングの基礎について見てきたが、決められたルールに沿うことで、少ない手間で URL を指定したページ遷移が実現できることがわかった。
次の項目では ルーティング時にパラメータの受け渡しを行う 方法について見ていく。

進んだ使い方

vue-router を使ったルーティングでは 任意の値をパラメータとして受け渡す ために

  • URL のパターンマッチングによるページ遷移
  • router.push を使ったページ遷移

といった方法が用意されている。

以下、それぞれの方法について見ていく。

パターンマッチングによるページ遷移

URL のパターンマッチングによってパラメータの受け渡しを行うケース。ここで挙げる例は以下のとおり。

  • ユーザ情報の詳細を持つコンポーネント UserDetail.vue がある
  • そのコンポーネントに対してユーザIDを URL で指定する
  • 指定したユーザ情報の詳細を表示するページに遷移する

基本 の項目でルーティングのための準備はできているので、本項では router.js への追記とユーザ情報の詳細を持つコンポーネント UserDetail.vue について扱う。

router.js への追記

パターンマッチングでのページ遷移の実現にあたり、まずは router.jsURL でのパラメータの受け渡し のための設定を記述する。

具体的には以下のとおり。

router.js
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.vuerouter.js で URL によるパターンマッチングでの遷移を行う際に指定されたコンポーネント。

前述の説明のとおり、下記のコードでは $route.params.id とすることで '/users/:id' で指定した id の値を取得 している。

UserDetail.vue
<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 のユーザ情報詳細

が、ぞれぞれ表示されることが確認できた。

スクリーンショット 2020-11-07 12.10.50.png

スクリーンショット 2020-11-07 12.11.14.png

ボタンアクションによるページ遷移

前掲の パターンマッチングURL上でパラメータがセットされたケース の例について触れた。
ここではボタンアクションによる パラメータの受け渡しを伴うページ遷移 について扱う。

ここで挙げる例は以下のとおり。

  • ユーザのリストを表示するコンポーネント UserList.vue と、その親コンポーネント Users.vue がある
  • コンポーネント UserList.vue でテーブルから任意のレコードを選択して Show more seleted... ボタンをクリックすることで
  • 指定したユーザ情報の詳細を表示するコンポーネント UserDetail.vue を呼び出す( 遷移する )

コードを見る前に

上記 3 つのコンポーネントの概要を表にすると以下のとおり。

コンポーネント 概要 子コンポーネント 備考
Users.vue User 情報を持つ UserList.vue
UserLive.vue User 情報をテーブルで表示する なし
UserDetails 指定された User 情報の詳細を表示する なし 前項 で扱っているのでここではコードを扱わない

このうち Users.vueUserDetail.vue は同じデータオブジェクトをそれぞれのコンポーネント内で定義している。
本来ならばこれらのデータは DB なり localStorage で持つなり、なんらかの手段でデータの共有化を図るべきなのだけれども、今回は ルーティングが主題 であるためデータの持ち方については考慮外とした。

Users.vue

Users.vue はユーザの一覧をオブジェクトとして持ち、画面描画時に子コンポーネントである UserList.vue にユーザ情報を渡すだけの単純なもの。

  • コンポーネントの親子関係
  • 親コンポーネント → 子コンポーネントへのデータ授受

についても少し見てみたいと思い試してみた。
( コンポーネント間のデータのやりとりについては、別途記事を設けて見ていきたい )

Users.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 を使用している。

UserList.vue
<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 の引数に nameparams プロパティをセットすることでルーティングを実現させている。

ここで nameparams.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 のユーザ情報詳細が表示される

ことが確認できた。

スクリーンショット 2020-11-07 11.46.55.png

スクリーンショット 2020-11-07 11.47.11.png

まとめ

基本

  • ルーティングには vue-router を使うと簡単に実現できる
  • ルーティングを管理するために router.js を実装して main.jsimport することで利用する
  • App.vue では以下を行ってうことで画面遷移を実現する
    • router-link で遷移先の指定
    • router-view で遷移先のページの表示

進んだ使い方

  • ルーティング時に任意の値をパラメータとして渡すことができる
  • そのための手段として以下を用いる
    • URL パラメータとして指定する
    • router.push 時にパラメータとして指定する
  • router.push 時に遷移先として name を指定することを 名前付きルート という

ソースコード

今回の記事で動作確認に使用したコードは下記にアップしております。
ご参考まで。
( 以下は ブランチのリンクですが、 master にもマージ済みです )
( master は Vue v3.x 系に移行しました. 本記事の内容は下記ブランチでご確認ください )

参考

公式

  1. Vue.js のコンポーネントを単独のファイルとして作成する機能
    拡張子「.vue」のファイルのことで<template>, <script>, <style> のブロックで構成されている。

68
87
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
68
87