Vue-RouterでSPAを作る



# はじめに
記事を閲覧いただきありがとうございます！
なかむらです！
Vue.jsのVue-Routerを使ってSPAを作ったので、その手順を解説します。

# SPAとは

僕がここでつらつら説明するより、
とてもシンプルに分かりやすく解説した動画がYoutubeにあったのでまずはこちらをご覧ください。

<iframe width="560" height="315" src="https://www.youtube.com/embed/xfGciVdbktI" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>

.....英語でしたね。
英語が苦手な方は、魂で聴き取っていただいて、
どうしても分からない方のために、彼が言っていた事を要約したいと思います。(結局w)

## SPAが無かった頃の場合
URLを叩いてWebサイトを表示させると、ブラウザからサーバーへ「Webサイトを見せてくれ！」とリクエストします。するとサーバーがWebサイトの<font color="Red">ホームページ</font>を送り返してくれて、ブラウザに表示されます。
続いて、ページA見たい場合、またサーバーへ「<font color="Red">ページA</font>をくれ！」と要求し、サーバーはページAを返してくれます。
ページBも同様のプロセスです。
このように新しいページを開く度にサーバーとのやり取りが発生し、その都度ブラウザのリロードが必要になります。
<img width="700" alt="not spa" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/530421/d5fcfda7-a6b4-21fe-9f12-78510d7e2eca.png">


## SPAの場合
SPAの場合はどうでしょうか。
最初にブラウザからサーバーへ「Webサイトを見せてくれ！」とリクエストを送ると、サーバーは<font color="Red">Webサイト一式のJS(JavaScript)</font>を送り返してきます。
ブラウザくんが手に入れたJavaScriptには全てのページが入っているので、ページAやページBを要求したとしても、いちいちサーバーへリクエストを送る必要がなくなります。
新しいデータが必要な時は、さすがにサーバーと通信しますが、少なくともページを開く時は通信する必要がなくなる訳です。
<img width="700" alt="spa" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/530421/a503c211-f272-589d-94e6-751d2dfa4f30.png">

SPAは上記のような仕組みで、各ページを素早く表示する事ができ、通信の負荷も減らす事ができます。
Webサイトが複雑になればなるほどその効果を発揮し、その最も代表的な例がGメールだそうです。
確かにGメールでは新規メールをチェックしたり、過去のメールを検索したりしても、ページをリロードすることはありませんね！

# SPA作成手順
それでは実際にVue.jsでSPAを作成していきます。
## 開発環境

Mac OS Catalina 10.15.7

vue.js 2.9.6

## 新規Vueプロジェクトを作成

```vue init webpack [プロジェクト名]```でvueプロジェクトを作成します。

```
vue init webpack vue-router-test
```
vueさんからいろいろ質問責めにあうので、面倒臭がらずに答えていきます。

- Project name : ```そのままEnter```
- Project description : ```そのままEnter```
- Author : ```そのままEnter```
- Vue build : ```standalone``` ※recommend for most usersって書いてたからコレにした
- Install vue-router? : ```Yes``` <font color="Red">※ここ重要！</font>
- Use ESLint to lint your code? : ```No``` ※テスト系は知見が無く、今回は全てNoで。。。
- Set up unit tests : ```No```
- Setup e2e tests with Nightwatch? : ```No```
- Should we run `npm install` for you after the project has been created? : ```(recom
mended) npm``` 

作成されたらプロジェクトのディレクトリに移動し、vueプロジェクトを起動してみます

```
cd vue-router-test
npm run dev
```
```Your application is running here: http://localhost:8080```と出力されるので
出てきたURLをブラウザで実行します。
以下のような画面が出ればOK！
<img width="600" alt="column count 1" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/530421/8d3c4d48-eba6-6c28-06f2-ed3a5bc68b7e.png">

## vue-router作成

vueプロジェクト作成直後は以下のような構成になっているかと思います。
※今回```src```配下のみ操作するのでそれ以外は割愛します。

```
vue-router-test/
  └ src/
     ├ components/
     │   └ HelloWorld.vue
     ├ router/
     │   └ index.js
     └ App.vue

```

### 各ページを作る(componentsファイル)

``` components/ ```配下に追加したいページを追加します。
```HelloWorld.vue```は使わないので消しちゃってもOK

```
vue-router-test/
  └ src/
     ├ components/
     │   └ HelloWorld.vue
     │   └ Home.vue
     │   └ Profile.vue
     │   └ Works.vue
     ├ router/
     │   └ index.js
     └ App.vue

```
``` src/components/ ```配下の各ページはとりあえず、そのページだと分かるように何か書いておきます。(後ほどページ遷移が出来るか確認するので)
```tenplate```タグ直下に複数のタグを書くとエラーになるのでご注意を！ 

```src/components/Home.vue
<template>
  <div>
    <h1>ホーム</h1>
    <p>最初に表示されるページ</p>
  </div>
</template>

<script>

</script>

<style>

</style>
```

### 各ページのルートを作成(index.js)

``` src/router/index.js ```を以下の通り変更します。

``` HelloWorld ```の真似をしてコンポーネントファイルの``` import ```を記載します。
``` export default new Router ```の中に各ページのルート情報を書いていきます。 
Homeは最初に表示されるページという事で ``` path: '/' ```と記載します。



```src/router/index.js
import Vue from 'vue'
import Router from 'vue-router'
import HelloWorld from '@/components/HelloWorld'
//ここから追加
import Home from '@/components/Home'
import Profile from '@/components/Profile'
import Works from '@/components/Works'
//ここまで追加

Vue.use(Router)

export default new Router({
  routes: [
//ここから追加
    //HelloWorldのrouteは削除
    {
      path: '/',
      name: 'Home',
      component: Home
    },
    {
      path: '/profile',
      name: 'Profile',
      component: Profile
    },
    {
      path: '/works',
      name: 'Works',
      component: Works
    }
//ここまで追加
  ]
})

```

ここまでの時点で```home.vue```が早速表示されます。

<img width="600" alt="column count 1" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/530421/cb475b3d-1834-8898-f8c6-8cba92321105.png">

## Bootstrap-vueをインストール
なぜBootstrap-vueを入れるかというと、画面にメニューバーを作成して、そこから各ページへ飛べるようにする為です。Bootstrap-vueじゃなくても作れるのかもしれませんが、僕は今のところコレしか知りません。。。。

プロジェクトのディレクトリにて```bootstrap-vue```をインストールします。

```
npm install bootstrap-vue
```
vueプロジェクト内でbootstrap-vueを呼び出せるよう、```import```します

```src/main.js
import Vue from 'vue'
import App from './App'
import router from './router'

//ここから追加
import BootstrapVue from 'bootstrap-vue'
import 'bootstrap/dist/css/bootstrap.css'
import 'bootstrap-vue/dist/bootstrap-vue.css'
Vue.use(BootstrapVue)
//ここまで追加

Vue.config.productionTip = false

/* eslint-disable no-new */
new Vue({
  el: '#app',
  router,
  components: { App },
  template: '<App/>'
})

```

## メニューバーを作成(App.vue)

App.vueはサイト全体のフレームのような役割をします。Components配下に作成したそれぞれのページは全てApp.vueの中で表示されます。


[Bootstrap-vue](https://bootstrap-vue.org/)の[Navbar](https://bootstrap-vue.org/docs/components/navbar#navbar)というコンポーネントを使ってメニューバーを作成します。
```<b-nav-item to="">```のところに```index.js```で指定した各ページのパスを記載します。
```<router-view/>```の部分でそれぞれのページが表示されます。

```src/App.vue
<template>
  <div id="app">
    <h1>Vue-Router-Test</h1>
    <b-navbar toggleable="lg" type="dark" variant="primary">
      <b-navbar-brand to="/">Home</b-navbar-brand>
      <b-navbar-toggle target="nav-collapse"></b-navbar-toggle>
      <b-collapse id="nav-collapse" is-nav>
        <b-navbar-nav>
          <b-nav-item to="/profile">Profile</b-nav-item>
          <b-nav-item to="/works">Works</b-nav-item>
        </b-navbar-nav>
      </b-collapse>
    </b-navbar>
    <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;
}
</style>

```

Bootstrapを使った事無い方へ
CSSを書いた事がある方であれば、以下のYoutubeプレイリストを見ればBootstrapを扱えるようになるかと思います！何だかよく分かんない方はこちらを先にやると良いかもです！
[Bootstrap 4入門(Youtube)](https://www.youtube.com/watch?v=FtkRIuWTf0E&list=PLh6V6_7fbbo9sHm8E3F7lZuDDxDJkheKD)

## 動作確認

ナビゲーションバーにある項目をクリックして、ページが表示されればOK！
あとはいい感じにオシャレなページを作って行きましょー！
<img width="600" alt="home" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/530421/28e062e2-ff76-998a-ad25-82afbf1e1110.png">

<img width="600" alt="profile" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/530421/9f7f5d79-70e5-abd1-f96c-61d9469ad807.png">

<img width="600" alt="works" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/530421/0b64fd9f-4998-17c6-1d44-f83b1c3c00e5.png">




# おわりに

Vue-routerを理解して、SPAを表現できるようになって
vue.jsがだいぶ楽しくなってきました！
興味がある方はぜひ作ってみてください！

分かりづらかったり、誤っている箇所があれば、コメントで教えていただけると幸いです。。。！