この記事では、SPAがはじめてという方向けに、”Vue.js”と”Vue Router”、”axios”を使った、SPAの作り方を紹介します。
そのため、「SPAのアプリケーションを作ってみたいけれど、どこから手をつければ良いかわからない」という方向けの内容となっています。
今回作成するアプリケーションは、「Ajaxで自分のIPアドレスを取得し、表示する」ことを目標としています。
実装する機能としてはシンプルですが、「画面遷移」や「Ajaxによるデータ通信」といった、アプリケーションに欠かせない処理を含んでいます。
この記事を参考にSPAを作ってみて、Vue.jsでSPAを作ることが、どういった感じかを掴んでいただければと思います。
作成するアプリケーションのイメージを下記に記載します。
- ホーム画面
-
IPを表示する画面
SPAとは何か?
SPAは、”Single Page Application(シングルページアプリケーション)”の略で、Webアプリケーションの設計方法の一つです。
SPAの特徴は、アクセス時に読み込むHTMLファイルは一つだけという点です。
最初にHTMLファイルを読み込んだ後は、Ajaxを使ってデータを取得し、画面内の要素を更新します。
通常のWebアプリケーションの場合、リクエストごとに画面全体をロードしなければなりません。
一方SPAでは、画面内で更新が必要な要素のみを置き換えます。
画面全体をロードする必要がないため、画面遷移中の表示を自由に変更したり、データの通信量を減らせたりする、というメリットがあります。
環境の説明
今回使用した環境は下記の通りです。
- システムのバージョン: macOS 10.13.4
- npmのバージョン: 6.2.0
- Vue CLIのバージョン: 3.0.1
Vue.jsプロジェクトの作成
本記事中の、$(ドルマーク)で始まる内容は、CLIコマンドを意味します。
“ターミナル”で実行してください。
まずはSPAプロジェクトを作成します。
“vue init”を実行すると、質問が表示されるので、下記を参考に選択してください。
$ vue init webpack hello-spa
===============================================
? Project name hello-spa // EnterでOK
? Project description A Vue.js project // EnterでOK
? Author // EnterでOK
? Vue build // EnterでOK。「Runtime + Compiler」
? Install vue-router? No // のちほどバージョンを指定してインストールするため、「n」を入力
? Use ESLint to lint your code? No // ESLintは扱わないため、「n」を入力
? Set up unit tests No // テストは扱わないため、「n」を入力
? Setup e2e tests with Nightwatch? No // E2Eテストは扱わないため、「n」を入力
? Should we run `npm install` for you after the project has been created? (recommended) npm // npmを選択
プロジェクトが作成できたら、”hello-spaディレクトリ”に移動します。
$ cd hello-spa
ローカルサーバを起動します。
$ npm run dev
“アプリケーションの起動に成功した”というメッセージが出るので、表示されたURLにアクセスします。
I Your application is running here: http://localhost:8080
次の画面が表示されていれば、プロジェクトのセットアップはOKです。
確認ができたら、
画面遷移 – Vue Router
“Vue Router”は、”Vue.js”のプラグインで、ルーティングを管理するために使用します。
Vue Router をインストールする
使用するVue Rouerのバージョンは”3.0.1″です。
npmでインストールするバージョンを指定する場合は、”@”のうしろにバージョン番号を指定します。
$ npm install vue-router@3.0.1
ページ用コンポーネントを作成する
今回作成するアプリケーションは、”ホーム画面”と”自分のIPを表示する画面”の2画面構成です。
各画面に対応するコンポーネントを用意します。
まずは、コンポーネントファイルを格納する、”pages”ディレクトリを作成します。
$ mkdir src/pages
src
├── App.vue
├── assets
├── components
├── main.js
└── pages
src/pages配下に ホーム画面用の”Home.vue”と、IP表示画面用の”SearchIp.vue”を作成します。
src/pages
├── Home.vue
└── SearchIp.vue
“Home.vue”と”SearchIp.vue”は、それぞれ下記のコードを入力してください。
“Home.vue”
<template>
<div id="home">
<div>
<h2>Vue.jsではじめるSPA</h2>
</div>
</div>
</template>
“SearchIp.vue”
<template>
<div id="search-ip">
<div>
<p>ここにIPが表示されます</p>
<div>
<input type="button" value="IPを取得する">
</div>
</div>
</div>
</template>
Vue Router の設定ファイルを用意する
次は、”Vue Router”の設定ファイルを用意します。
“srcディレクトリ”の直下に”router.js”を作成してください。
“router.js”の設定内容は下記の通りです。
“src/router.js”
import Vue from 'vue';
import VueRouter from 'vue-router';
import Home from '@/pages/Home.vue';
import SearchIp from '@/pages/SearchIp.vue';
Vue.use(VueRouter);
var router = new VueRouter({
routes: [
{
path: '/',
component: Home
},
{
path: '/search_ip',
component: SearchIp
}
]
});
export default router;
“routes”キーの配列にオブジェクトを追加しました。
このオブジェクト内の”path”と”component”で、URLとコンポーネントが紐付けられます。
作成した”router.js”は、”src/main.js”で読み込みます。
次のコード中に、「この行を追加」とコメントしている処理を追加しましょう。
“src/main.js”
// The Vue build version to load with the `import` command
// (runtime-only or standalone) has been set in webpack.base.conf with an alias.
import Vue from 'vue'
import App from './App'
import router from './router.js' // この行を追加
Vue.config.productionTip = false
/* eslint-disable no-new */
new Vue({
el: '#app',
router: router, // この行を追加
components: { App },
template: '<App/>'
})
まだ追加したコンポーネントを表示することはできません。
“router-link”タグとrouter-view”タグを使って、画面遷移用のリンクとコンポーネントを表示できるようにしましょう。
そのために、”src/App.vue”を次のように書き換えます。
<template>
<div id="app">
<router-link to="/">Home</router-link>
<router-link to="/search_ip">Search IP</router-link>
<router-view />
</div>
</template>
<script>
export default {
name: 'App',
components: {
}
}
</script>
- ホーム画面
“router-link”タグの”to”属性で遷移先のURLを指定しています。 -
IPの表示画面
“router-view”タグは、画面用のコンポーネントに置換されます。
画面遷移の動作確認
以上で、ルーティングの設定が完了しました。
ローカルサーバを起動して、コンポーネントを表示できるかどうか確認します。
$ npm run dev
“http://localhost:8080” にアクセスして、”Home.vue”の内容が見えていればOKです。
画面上部の”Home”と”Search IP”のリンクをクリックすると、それぞれの画面が表示されます。
- ホーム画面
-
IPの表示画面
Ajaxリクエスト – axios
画面の遷移ができるようになったので、次は「Ajaxを使ってデータの取得する」機能を実装してみましょう。
IPを表示する
本例では、”httpbin.org”にリクエストを送信し、返ってきたレスポンスを取得します。
その中から、自分のIPアドレスを取得して、画面に表示します。
「IPを取得」ボタンが押されたときに呼び出されるメソッドを定義します。
“SearchIp.vue”を下記の実装に変更してください。
<template>
<div id="search-ip">
<div>
<p v-text="ip">ここにIPが表示されます</p>
<div>
<input @click="getIp" type="button" value="IPを取得">
</div>
</div>
</div>
</template>
<script>
export default {
name: 'SearchIp',
data() {
return {
ip: ''
}
},
methods: {
getIp() {
this.ip = '111.111.111.111';
}
}
}
</script>
“@click”で、ボタンのonClickと”getIp()”メソッドを紐づけています。
メソッドでは、”this.ip”を変更するようになっています。
“dataのip”は”v-text”を設定したpタグに表示されるため、「IPを取得」ボタンをクリックすると、”ここにIPが表示されます”が”111.111.111.111″に切り替わります。
これで、「IPを取得」ボタンに対応するメソッドが用意できました。
次はリクエストを送信して、自分のIPを取得する処理を追加します。
HTTPリクエストの送信には、“axios”を使用します。
まずは”npm install”で、”axios”をインストールしましょう。
$ npm install axios@0.18.0
axiosは”main.js”でインポートすることで、コンポーネント内で使用できるようになります。
“src/main.js”にaxiosのimport文を追加します。
“Vue.prototype.$axios”にインポートしたaxiosを設定します。
コンポーネント内では、”this.$axios”という書き方でaxiosを呼び出せるようになります。
// The Vue build version to load with the `import` command
// (runtime-only or standalone) has been set in webpack.base.conf with an alias.
import Vue from 'vue'
import App from './App'
import router from './router.js'
import axios from 'axios' // この行を追加
Vue.config.productionTip = false
Vue.prototype.$axios = axios; // この行を追加
/* eslint-disable no-new */
new Vue({
el: '#app',
router: router,
components: { App },
template: '<App/>'
})
“SearchIp.vue”に、axiosを使ったリクエストの送信処理を実装します。
実装内容は下記を参照ください。
<template>
<div id="search-ip">
<div>
<p v-text="ip">ここにIPが表示されます</p>
<div>
<input @click="getIp" type="button" value="IPを取得">
</div>
</div>
</div>
</template>
<script>
export default {
name: 'SearchIp',
data() {
return {
ip: 'ここにIPが表示されます'
}
},
methods: {
getIp() {
this.ip = 'IPを取得しています';
this.$axios.get('https://httpbin.org/get')
.then((response) => {
this.ip = response.data.origin;
})
.catch((reason) => {
this.ip = 'IPの取得に失敗しました';
});
}
}
}
</script>
書き換えができたら、「IPを取得」ボタンを押してください。
“ここにIPが表示されます”のメッセージが、自分のIPのアドレスに更新されます。
今回の目標であった、”シンプルなSPA”の作成はここまで完了です。
ただ、このままだと見た目が寂しいので、デザインを変更します。
デザイン変更
ライブラリをインストールする
デザインの調整には、SASS(SCSS)を使います。
scssファイルをコンパイルするためには、ライブラリを追加する必要があります。
下記のnpmコマンドを実行して、インストールしてください。
$ npm install sass-loader node-sass --save-dev
CSSのリセットは、Bootstrapの”Reboot.css”を用います。
$ npm install bootstrap@4.1.3
アプリケーションに”Reboot.css”を読み込ませるために、scssファイルを用意します。
“src/assets/scss/styles.scss”を作成してください。
“styles.scss”には、”Reboot.css”のインポートを記述します。
@import "bootstrap/dist/css/bootstrap-reboot.min.css";
“src/main.js”で、”styles.scss”を読み込みます。
// The Vue build version to load with the `import` command
// (runtime-only or standalone) has been set in webpack.base.conf with an alias.
import Vue from 'vue'
import App from './App'
import router from './router.js'
import axios from 'axios'
import './assets/scss/styles.scss'; // この行を追加
Vue.config.productionTip = false
Vue.prototype.$axios = axios;
/* eslint-disable no-new */
new Vue({
el: '#app',
router: router,
components: { App },
template: '<App/>'
})
デザインを変更する
背景画像を設定します。
お好みの画像を、”src/assetsディレクトリ”に保存してください。
本例では、”src/assets/background.jpg”を使用します。
$ tree src/assets
==================
src/assets
├── background.jpg
├── logo.png
└── scss
└── styles.scss
“App.vue”を下記の内容に変更します。
<template>
<div id="app">
<div class="bg-image">
<ul class="navigation">
<li class="navigation-link">
<router-link to="/">Home</router-link>
</li>
<li class="navigation-link">
<router-link to="/search_ip">Search IP</router-link>
</li>
</ul>
<router-view class="main"/>
</div>
</div>
</template>
<script>
export default {
name: 'App',
components: {}
}
</script>
<style lang="scss">
#app {
height: 100vh;
}
.navigation {
padding-top: 5%;
display: flex;
list-style: none;
justify-content: flex-end;
}
.navigation-link {
width: 100px;
text-align: center;
margin-right: 2rem;
a {
padding: 8px;
color: #ffffff;
text-decoration: none;
display: block;
font-size: 0.9rem;
text-transform: uppercase;
&.router-link-exact-active {
border-bottom: 2px solid #e67e22;
}
&:hover {
transition: border-bottom 0.2s;
border-bottom: 2px solid #e67e22;
}
}
}
.bg-image {
background-image: linear-gradient(rgba(0, 0, 0, 0.7), rgba(0, 0, 0, 0.7)), url("assets/background.jpg");
background-position: center;
background-size: cover;
height: 100%;
}
.main {
height: 85%;
}
</style>
“Home.vue”は次の内容にしてください。
<template>
<div id="home">
<div class="hero-text">
<h2>Vue.jsではじめるSPA</h2>
</div>
</div>
</template>
<style lang="scss">
#home {
display: flex;
align-items: center;
justify-content: center;
}
.hero-text {
font-size: 2rem;
color: #ffffff;
}
</style>
最後に”SearchIp.vue”を更新します。
<template>
<div id="search-ip">
<div>
<p v-text="ip" class="ip-text"></p>
<div class="btn-area">
<input @click="getIp"
class="btn"
type="button"
value="IPを取得する">
</div>
</div>
</div>
</template>
<script>
export default {
name: 'SearchIp',
data() {
return {
ip: 'ここにIPが表示されます'
}
},
methods: {
getIp() {
this.ip = 'IPを取得しています';
this.$axios.get('https://httpbin.org/get')
.then((response) => {
this.ip = response.data.origin;
})
.catch((reason) => {
this.ip = 'IPの取得に失敗しました';
});
}
}
}
</script>
<style lang="scss">
#search-ip {
display: flex;
align-items: center;
justify-content: center;
}
.btn-area {
display: flex;
align-items: center;
justify-content: center;
}
.ip-text {
font-size: 2rem;
color: #ffffff;
}
.btn {
background-color: #ffffff;
border-color: #ffffff;
color: #e67e22;
padding: 10px 20px;
border-radius: .3em;
cursor: pointer;
display: block;
&:hover {
background-color: #e67e22;
border-color: #e67e22;
color: #ffffff;
}
&:focus {
outline: 0;
}
}
</style>
デザインを調整した結果が、下記の画像です。
- ホーム画面
-
IPの表示画面 表示前
-
IPの表示画面 表示後
まとめ
Vue.jsを使った、SPAの作り方について紹介しました。
今回作ったアプリが、SPAの作り方を理解する助けになれば幸いです。
まだ物足りない方は、APIを自作したり、画面遷移時にローディングを表示したり、思いつく変更を実装してみてください。
作成したアプリは、Firebaseで公開することができます。詳細については、次の記事を参照ください。

最後までお読みいただき、ありがとうございます。
もしこの記事が役に立ったと感じたら、はてなブックマークボタン等を押していただけると励みになりますので、ぜひお願いします。