VueRouterを使用してSPAを実現

こんにちは、デザインシステム室の菅野です。
ついこの間、Railsで作られているサービスにフロント強化ためにVue.jsを導入し、今回Vue.jsを初めて触り、VueRouterを使用して一部SPAにしたので実装方法をおさらいしたいと思います。


VueRouterって?

VueRouterはVue.jsの公式ルータであり、webページのルーティングを実装してくれる公式の
プラグインです。
機能としては以下のとおりです。

  • ネストされたルート/ビューマッピング
  • モジュール式、コンポーネントベースのルータ構造
  • ルートパラメータ、クエリ、ワイルドカード
  • Vue.js の transition 機能による、transition エフェクトの表示
  • 細かいナビゲーションコントロール
  • 自動で付与される active CSS クラス
  • HTML5 history モードまたは hash モードと IE9 の互換性
  • カスタマイズ可能なスクロール動作

SPAはシングルページアプリケーションの略で、単一のwebページでコンテンツを切り替えることで、ページ遷移のストレスが無くしてるくれるとっても便利なものです。

ディレクトリ構造完成形(使用部分のみ)

app
 ├─javascript
 │    │   ├─packs
 │    │   │   └─application.js
 │    │   ├ src
 │    │   │   └─pages
 │    │   │      ├─Home.vue
 │    │   │      ├─Hoge.vue
 │    │   │      └─Fuga.vue
 │    │   └───components
 │    │          ├─Header.vue // ヘッダーコンポーネント      
 │    │          └─Footer.vue // ヘッダーコンポーネント
 │    ├─App.vue
 │    └─routes.js
 │
 ├─controller
 │    └─foo
 │        ├─foo_controller.rb
 │        └─application_controller.rb
 ├─views
 │   └─foo
 │        ├─foo
 │        │   ├─home.html.erb
 │        │   └─application_controller.rb
 │        └─layouts
 │             └─application.html.erb           
 └─config
     └─routes.rb  

1.インストール

今回はyarnを使ってインストールをしました。

yarn add Vue-Router

2.Vue側設定

routes.jsファイルを以下のように作成し、Routerインスタンスを作成します。

// routes.js

// import
import Vue from 'vue';
import VueRouter from 'vue-router'; // Vue Routerをインポート
import Home from './src/pages/Home.vue'; // この部分をSPAにする
import Hoge from './src/pages/Hoge.vue'; // この部分をSPAにする
import Fuga from './src/pages/Fuga.vue'; // この部分をSPAにする

// routerの設定とインスタンス生成
const routes = [
  {path: '/', component: Home}, // パスと表示するコンポーネントを設定
  {path: '/hoge', component: Hoge}, // パスと表示するコンポーネントを設定
  {path: '/Fuga', component: Fuga}, // パスと表示するコンポーネントを設定
];

export default new VueRouter({ 
  mode: 'history',   // histroyモードにすることでURLに#が入らないらしい(※1)
  routes
});

(※1)[Vue.js] vue-routerのhashモードとhistoryモードの違いをざっくり理解する

以下のようにしてapplication.jsでroutes.jsを読み込みます。

// packs/application.js

import Vue from 'vue'; 
import VueRouter from 'vue-router';
import router from '../routes'; // routes.js読み込み
import App from '../app';

//vue-routerをインストール
Vue.use(VueRouter);

document.addEventListener('DOMContentLoaded', () => {
  new Vue({
    el: '#application',
    router,
    render: (h) => h(App),
  });
});

描画されるApp.vueを設定

// javascript/App.vue

<template>
  <div>
    <header-component />  // ヘッダーコンポーネント   
    <v-main>
      <router-view /> // routes.jsに設定したコンポーネントが描画される
    </v-main>
    <v-footer>
      <footer-component /> // フッターコンポーネント
    </v-footer>
  </div>
</template>

<script>
import HeaderComponent from './src/components/Header';
import FooterComponent from './src/components/Footer';

export default {
  components: {
    HeaderComponent,
    FooterComponent,
  },
}
</script>

ヘッダーにページ切り替え用のボタンを設置

// Header.vue

<template>
  <header>
    <div class="nav-block">
      <div class="logo">
        <a
          href="/"
          style="font-size:1.953rem;font-weight:bold;color:#717171;text-decoration: none;"
        >
          <p sytle="padding=20px;"> サービス名 <span>for Business</span></p>
        </a>
      </div>
      <ul class="nav-list">
        <li>
      // ボタン設置 hogeコンポーネントを描画する
          <v-btn to="/hoge" rounded x-large color="#AACD06" class="button1"
            >お問い合わせ</v-btn
          >
        </li>
        <li>
      // ボタン設置 fugaコンポーネントを描画する
          <v-btn to="/fuga" rounded x-large color="#F8601E" class="button2"
            >資料ダウンロード</v-btn
          >
        </li>
      </ul>
    </div>
  </header>
</template>

3.Rails側の設定

// foo_controller.rb

class Foo::FooController < Foo::ApplicationController

  def home
  end

end
// ad_inquiry/application_controller.rb

class AdInquiry::ApplicationController < ApplicationController
  layout 'foo/layouts/application' // レイアウトを指定
end
// routes.rb

namespace :foo do
  get '/', to: 'foo#home'
end

rails側で呼ばれるviewファイル。
SEOのために以下のように追記

// foo/foo/home.html.erb

<% self.html_title = "サービスタイトル" %>
<% self.meta_description = "ディスクリプション" %>

レイアウトの設定
vue側で認識できるようにマウント用のIDを設定
(application.jsのelで設定しているもの)

// foo/foo/application.html.erb

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <title><%= yield(:html_title).presence || 'サービス' %></title>
    <meta name="description" content="<%= yield(:meta_description).presence || '' %>" />
    <meta name="viewport" content="width=device-width,initial-scale=1" />
    <meta http-equiv="Pragma" content="no-cache">
    <meta http-equiv="Cache-Control" content="no-cache">
    <%= csrf_meta_tags %>

    <%= stylesheet_pack_tag 'ad_inquiry/application', media: 'all', 'data-turbolinks-track': 'reload' %>
    // packs下のapplication.jsを読み込むために設定
    <%= javascript_pack_tag 'application', 'data-turbolinks-track': 'reload' %>
  </head>

  <body>
    <div id="application"></div> // マウント用のID
  </body>
</html>

まとめ

私自身vueを触るのが初めてだったので、書き方が間違っている部分があるかもしれません、、、まぁそこは勉強しながらおいおい改善していきたいと考えております。

ファンデリーではチャレンジすることを尊重してくれる文化なので、今回のようなVueを触ってみたいという私の思い(わがまま)も尊重してくれました!

現在デザイン・システム室では新しいメンバーを大募集しています。
デザイン、フロントエンド 、サーバーサイドまだまだメンバーが足りていないので、
ぜひ興味をお持ちの方は下記エントリーフォームから応募お願いいたします!
ご連絡お待ちしております!

デザイン・システム室へのご質問 >

募集要項およびエントリーフォーム >