ゆるっとVue.js勉強会
Vue.jsハンズオン「Vue.jsでSPAを作ろう」

えっ!?Vue.jsに触れて2ヶ月で、
勉強会のメンター????

場 所:ロジカルスタジオ会議室アドリア(4F)
時 間:12月17日(火) 19:20~21:00
登壇者:上平さん

こんにちは、ロジカルスタジオのフロントエンドエンジニア、T.Kです。
なんと早いもので、外部向け勉強会「ゆるっとStudy」も3回目となりました😳😳😳
これもひとえに皆様のご愛顧のお陰です、誠にありがとうございます!
弊社マスコットキャラクターロージーも嬉しそうです

 

(上記画像は勉強会へご来場の皆様に配布中のステッカーです。ぜひご活用ください!)

さてさて、今回のテーマは?

今回の勉強会は、前回のハンズオンに続き、Vue.jsがテーマです。
今回は、この便利なVue.jsを使ってSPAを作るということが目的となります!
なんと今回、予定の参加人数があっという間に埋まり、当勉強会の宣伝をブログで出来ないほどでした…。
Vue.js×ハンズオンのニーズの高さをひしひしと感じる今日このごろです。
(ちなみにこのテーマの発案者は私、T.Kです…

SPAとは?

シングルページアプリケーションsingle-page applicationSPA)とは、単一のWebページのみから構成することで、デスクトップアプリケーションのようなユーザ体験を提供するWebアプリケーションまたはWebサイトである。必要なコード(HTMLJavaScriptCSS)は最初にまとめて読み込むか、ユーザの操作などに応じて動的にサーバと通信し、必要なものだけ読み込みを行う。

出典 Wikipedia

SPAでは、その中のリンクを押すとURLは変わりますが、その遷移は擬似的なものであり、実際はページ遷移はされません。
その証拠に、SPA内のリンクを押してもブラウザ側では読み込み中の表示が出ません!
有名なSPAの例として、Twitterが挙げられます。

SPAのメリットは?

では、「SPAにはどのようなメリットがあるの?」というところを見ていきましょう!

高速な画面遷移

SPAでないサイトだと、共通パーツ(ヘッダ、フッタ、ナビetc…)がページ遷移のたびに読み込まれるため、読み込み時間のロスとなります。
SPAでサイトを作ると共通パーツは一度しか読み込まれず、共通でないパーツのみ適宜読み込まれるので効率的です!

バックエンドとフロントエンドで開発を切り分けられる

SPAでページを作ると、バックエンドとのやり取りはAPIで行われます。
フロント側でphpなどを書く必要がないため、バックエンドとフロントエンドの動きを完全に別にできる、というわけです!

Vue.jsを使用すると、このように様々なメリットを持ったSPAが比較的簡単に作ることができます!
SPA作りを通して、Vue.jsに関する様々な概念
について理解を深めていきましょう!

今回の勉強会の登壇者・メンター

登壇者は今回も、弊社Vue.jsの勉強会といえばこの方、上平さん!
そして今回は、私T.Kがメンターとして参加させて頂きました!
(メンターについては過去の弊社ブログ記事参照)
Vue.jsに触れて2ヶ月、Vue.jsの案件にも加えて頂き、ある程度慣れてきたとはいえ、
人に教えられるのかと言われると若干心配でしたが、上平さんに背中を押されて挑戦!
私以外にも、上平さん、有澤さん、sanadiさん、そしてメンター初挑戦の社員が一人、メンターとして参加しました。

メンター参加は、

  • Vue.js の基礎ができる
  • やったことがある

という方ならどなたでもして頂けます!

また今回も、前回に引き続き、勉強会中にTwitterで感想を随時参加者の皆様に書いて頂く形で進行しました。
ハッシュタグ「#ゆるっとStudy」をツイートにつけて頂くと、それをロージーがTwitter上で拾っていきます。
ご挨拶・会場案内の後、いざ、勉強会(と、私の初メンター)スタートです!

環境構築

Vue.jsでSPAを作るには、環境構築が必要となります。
では、環境構築の方法を見ていきましょう。

Node.jsのインストール

Vue.jsでのSPA開発のためにNode.jsを使用するので、まずはNode.jsをダウンロードします。
Node.jsはこちらから無料でダウンロード可能です!
インストールしたら、以下のコマンドをコマンドプロンプトに入力します。

node -v
npm -v

バージョンが表示されれば、インストールが成功している証拠です!

Vue CLIのインストール

では、次にVue CLIをインストールします。
まずコマンドプロンプトで以下を入力して、グローバルにVue CLIをインストールします。

npm install -g @vue/cli

そして、以下を入力してバージョンが表示されていれば、インストール成功です!

vue --version

Vue.js環境のセットアップ

まずコマンドプロンプト内で、環境を構築するディレクトリの一つ前(../)の階層に行きます。
そして、Vue.jsの環境を作成するために、以下のコマンドを入力します。

vue create spa

すると以下のように表示されます。

Vue CLI v4.1.1
? Please pick a preset: (Use arrow keys)
❯ default (babel, eslint)
Manually select features

矢印キーでdefault (babel, eslint)を選択し、エンターキーを押します。
しばらく待つとコマンドプロンプトが停止します。これでVue.jsの環境構築は完了です!
完了すると「spa」というフォルダが生成されます。中はこのような構成となっています。

.
├── README.md
├── babel.config.js
├── node_modules
│   └── *
├── package-lock.json
├── package.json
├── public
│   ├── favicon.ico
│   └── index.html
└── src
   ├── App.vue
   ├── assets
   │   └── logo.png
   ├── components
   │   └── HelloWorld.vue
   └── main.js

サーバーの立ち上げ

コマンドプロンプト内で、生成されたフォルダ「spa」へ行き、以下を入力します。

npm run serve

すると以下のように表示されます。

DONE Compiled successfully in 2875ms 12:52:04 PM


App running at:
- Local: http://localhost:8080/
- Network: http://192.168.11.144:8080/

Note that the development build is not optimized.
To create a production build, run npm run build.

そしてブラウザ上でhttp://localhost:8080/を表示すると、以下のようなページが表示されます。

無事、Vue.jsの環境が構築されています!

Vue Routerを導入する

SPAは「URLによって画面を切り替える」ということが欠かせません。
Vur RouterはSPAのそういった挙動を簡単に提供してくれるモジュールです。

まずコマンドプロンプトでフォルダ「spa」まで行き、以下を入力します。

npm install vue-router

そして、src/に「routes」というフォルダを作成した後、
src/routes/に「index.js」というファイルを作成し、内容を以下のようにします。

import Vue from 'vue'
import VueRouter from 'vue-router'

Vue.use(VueRouter)

export default new VueRouter({
mode: 'history',
routes: []
})

次に、src/main.jsの内容を以下のようにします。

import Vue from 'vue'
import App from './App.vue'
import router from './routes'

Vue.config.productionTip = false

new Vue({
  router,
  render: h => h(App),
}).$mount('#app')

そして、src/App.vueを以下のように書き換えます。
<router-view></router-view>の箇所に、コンポーネントが表示されます。

<template>
  <div id="app">
    <router-view></router-view>
  </div>
</template>

<script>
export default {
  name: 'app',
}
</script>

<style>
#app {
  font-family: 'Avenir', Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}
</style>

コンポーネントとは

コンポーネントとは、サイト中で使われるパーツのようなものです。詳しくはこちらをご覧ください。
Vue.jsは、コンポーネントで使われるHTML、CSS、Javascriptを.vueファイルにまとめて保存することができます。
Vue Routerでは、.vueファイルとして作ったコンポーネントを<router-view></router-view>の部分に表示することでページのコンテンツを表します。

.vueファイルの見方

<template></template>…HTMLを記述します。

<script></script>…Javascriptを記述します。name: 'app',は、この.vueファイルをappというコンポーネントとする、という意味です。

<style></style>…CSSを記述します。

Vue Routerでページを作ってみる

では、ページのコンテンツを.vueファイルで作っていきましょう!

ページコンポーネントを作る

まず、src/pages/に「Index.vue」というファイルを作ります。
ファイル名の頭文字が小文字だと認識されないので、ご注意ください!

<template>
  <div>Indexページです</div>
</template>

<script>
export default {}
</script>

<style scoped>

</style>

<style scoped>とは?

.vueファイルの<style>scopedをつけると、<style>内に書いたプロパティがそのコンポーネント内のみで効くようになります。
詳しく知りたい方はこちらをご覧ください!

そして、同様に「src/pages/Detail.vue」を作成します。

<template>
  <div>Detailページです</div>
</template>

<script>
export default {
}
</script>

<style scoped>

</style>

ルーティングする

先程作ったIndex.vueとDetail.vueをルーティングしましょう!
src/routes/index.jsにこのように追記します。

import Vue from 'vue'
import VueRouter from 'vue-router'

Vue.use(VueRouter)

import Index from '../pages/Index'
import Detail from '../pages/Detail'

export default new VueRouter({
  mode: 'history',
  routes: [
    { path: '/', component: Index },
    { path: '/detail', component: Detail },
  ]
})

import Index from '../pages/Index'
import Detail from '../pages/Detail'
でIndex.vueとDetail.vueをそれぞれIndexとDetailとして読み込み、
{ path: '/', component: Index },
{ path: '/detail', component: Detail },
で、Index(つまりIndex.vue)に/を、
Detail(つまりDetail.vue)に/detailを割り当てています。

これで、http://localhost:8080/ にアクセスするとIndex.vueの内容が、
http://localhost:8080/detail/ にアクセスするとDetail.vueの内容が表示されるようになりました!

リンクを設置する

リンクを設置し、別ページに移れる(=表示している.vueファイルを切り替えられる)ようにします!
src/App.vueに以下のように追記します。

<template>
  <div id="app">
    <router-link to="/">Index</router-link>
    <router-link to="/detail">Detail</router-link>
    <router-view></router-view>
  </div>
</template>

<script>
export default {
  name: 'app',
}
</script>

<style>
#app {
  font-family: 'Avenir', Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  color: #2c3e50;
  margin-top: 60px;
}
</style>

<router-link>でリンクを設置でき、toでリンク先を設定します。toの値は先程設定したパスを設定します。
<router-link to="/hoge"><a href="/hoge">に置き換えられて表示されます!
<router-link>はApp.vueだけでなく、Index.vueやDetail.vueにも書くことができ、きちんとリンクとして動作します。
もちろんページ遷移時「読み込み中」の表示は出ません!

これで、リンク機能及びルーティング機能を持ったSPAが完成しました!㊗㊗㊗

やってみた感想

コンポーネントの概念は初見では戸惑いますが、すぐ慣れました!
SPAはメリットが大きいため、普段のウェブサイト制作でも使ってみたいと思いました。

APIを取得してページに表示させる

とりあえずこれでSPAは完成ですが、ここからはさらにこのSPAをアプリケーションっぽくしていきたいと思います!
ここではGoogle Books APIを使って本のデータを取得し、Index.vueに本の一覧を、Detail.vueに本の詳細を表示していきます。

axiosをインストールする

axiosはブラウザやnode.jsで動くHTTPクライアントです。以下のコマンドを入力し、インストールします。

npm i axios -S

Google Books APIを取得してページに表示する

src/pages/Index.vueを以下の内容に修正します。

<template>
  <div>
    <div>Indexページです</div>
    <div v-for="book in books" :key="book.id">
    <img :src="book.volumeInfo.imageLinks.thumbnail" alt="">
    <p>タイトル : {{ book.volumeInfo.title }}</p>
    <p>サブタイトル : {{ book.volumeInfo.subtitle }}</p>
    <hr>
  </div>
</div>
</template>

<script>
import axios from 'axios'
const ENDPOINT = 'https://www.googleapis.com/books/v1/volumes'
const CONFIG = {
  params: {
    q: 'Vuejs'
  }
}
export default {
  data() {
    return {
      books: []
    }
  },
  created() {
    axios.get(ENDPOINT, CONFIG).then((res) => {
      if (res.data) {
        this.books = res.data.items
      }
    })
  }
}
</script>

<style scoped>

</style>

まずcreated(DOMが作られていない状態で実行される)でbooks[]にタイトルにvuejsが含まれる本のデータを登録し、
各ディレクティブを使って一覧表示します。
ディレクティブについては以下のリンクをご覧ください。

詳細情報をDetail.vueにリンクする

Index.vueの表示されている本の情報を<router-link>で囲み、Detail.vueにリンクさせます。

<template>
  <div>
  <div>Indexページです</div>
  <div v-for="book in books" :key="book.id">
  <router-link :to="`/detail/${book.id}`">
    <img :src="book.volumeInfo.imageLinks.thumbnail" alt="">
    <p>タイトル : {{ book.volumeInfo.title }}</p>
    <p>サブタイトル : {{ book.volumeInfo.subtitle }}</p>
  </router-link>
  <hr>
  </div>
  </div>
</template>


<script>
import axios from 'axios'
const ENDPOINT = 'https://www.googleapis.com/books/v1/volumes'
const CONFIG = {
  params: {
  q: 'Vuejs'
  }
}
export default {
  data() {
  return {
  books: []
  }
  },
  created() {
  axios.get(ENDPOINT, CONFIG).then((res) => {
  if (res.data) {
    this.books = res.data.items
  }
  })
  }
}
</script>


<style scoped>


</style>

:toで`/detail/${book.id}`にリンクさせます。${book.id}には本のID情報が入ります。

/detailの後にidを渡す

/detail/${book.id}には現時点ではなにもページが割り当てられていません。
そのため、routes/index.jsを以下のように修正し、/detail/${book.id}にDetail.vueを割り当てます。
${book.id}の値が何であっても、Detail.vueの内容が表示されます。

import Vue from 'vue'
import VueRouter from 'vue-router'


Vue.use(VueRouter)


import Index from '../pages/Index'
import Detail from '../pages/Detail'


export default new VueRouter({
  mode: 'history',
  routes: [
    { path: '/', component: Index },
    { path: '/detail/:id', component: Detail },
  ]
})

これで/detail/${book.id}にリンクされるようになりました。

DetailでIDを受け取り、APIで表示する

以上の状態でリンクを押して/detail/${book.id}へ移動しても、何も表示されません。
そこで、src/pages/Detail.vueを以下のようにし、Detail.vueに詳細情報が表示されるようにします。

<template>
  <div v-if="book">
    <img :src="book.volumeInfo.imageLinks.thumbnail" alt="">
    <p>タイトル : {{ book.volumeInfo.title }}</p>
    <p>サブタイトル : {{ book.volumeInfo.subtitle }}</p>
    <p>説明 : {{ book.volumeInfo.description }}</p>
    <a v-if="book.saleInfo.buyLink" target="_blank" :href="book.saleInfo.buyLink">購入ページへ</a>
  </div>
</template>

<script>
import axios from 'axios'
const ENDPOINT = 'https://www.googleapis.com/books/v1/volumes'
export default {
  data() {
    return {
      book: null
    }
  },
  created() {
    const id = this.$route.params.id
    axios.get(`${ENDPOINT}/${id}`).then((res) => {
      if (res.data) {
        this.book = res.data
      }
    })
  }
}
</script>

<style scoped>

</style>

DOMが読み込まれる前に、 createdでリンクに対応する本のデータを読み込み、<template>内で表示します。

これで完成です!お疲れ様でした!

親睦会

今回のゆるっとStudyでも、お菓子やお酒を囲んでの親睦会が行われました!
私含め弊社社員も数人参加し、参加者の皆様とお話させて頂きました。
参加者の方は、Vue.js初心者や、Vue.jsを普段使っていない方が多かったようでした。

Vue.jsハンズオン「Vue.jsでSPAを作ろう」を終えて

今回の「Vue.jsでSPAを作る」というテーマは私も個人的に非常に興味があったテーマであり、
大変みのりの多い勉強会になったのではないかと感じています!
そして私と同じように「普段のコーディングもぜひこの方法でやりたい!」と感じた方も多いのではないでしょうか??

また私が初めてメンターを務める勉強会でした。
私も参加者の皆様からの質問にいくつか答えさせて頂きましたが、適切に答えられたか不安です。。。
これから適切な回答ができるよう、精進していきたいと思います。
疑問点の残った方は、

から受け付けておりますので、お気軽にお問い合わせくださいませ!

参加スタッフ:上平 有澤 ドラゴン ヤッサン アッカリーン のてぃこ T.K ノート ロージー カール

弊社へのご用命、お問い合わせ、ご相談、勉強会のご質問、あとStudy Studioのレンタル依頼等はコチラから!▼

ブログ記事