Vue.js v-ifを使ってSPA(single page application)を自分なりに実装してみた

# 初めに
断言します。役に立ちません。ページを開いてしまった方、お手間を取らせてしまい申し訳ございません。こわいので初心者タグを2つ付けました。

# 最近勉強したローカルコンポーネント

スタート画面をローカルコンポーネントを使って実装する。ドヤ顔で実装する。


```js
var Start = {
  template: `<h1>スタート画面</h1>`
}

var app = new Vue({
  el: '#app',
  components: {
    'start-component': Start
  }
})
```

```html
  <div id="app">
    <start-component></start-component>
  </div>
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/621414/4f2696a6-3cf5-b8b5-a4f4-2e622e088950.png)

続いて切り替えボタンを作成する。

- 注意点
    - templateに複数のタグを置くことはできない

このことに注意しないと<strong>コンパイルエラー</strong>となる。

```js

var Start = {
  template: `
  <div>
    <h1>スタート画面</h1>
    <button class="button">start</button>
  </div>`
}

var app = new Vue({
  el: '#app',
  components: {
    'start-component': Start
  }
})
```


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/621414/ef584d40-4cc5-d1d1-2704-6a0b4b43c7a7.png)

# v-if 召喚

ここからは押すと文字とボタンが消えるボタン作成をする。

以下のコードでは次の動作を実現している。

1. ボタンを押す
2. メソッドstartButtonが発動
3. v-ifの中身がfalseにチェンジ

```js
var Start = {
  template: `
  <div v-if="this.isStartScreen">
    <h1>スタート画面</h1>
    <button v-on:click="startButton" class="button">start</button>
  </div>`,
  data: function() {
    return {
      isStartScreen: true
    }
  },
  methods: {
    startButton: function() {
      this.isStartScreen = false;
    }
  }
}
```

# 切り替わった後の画面作成

- htmlファイルに新しいコンポーネントmain-component追加

```html
  <div id="app">
    <sample-component></sample-component>
    <main-component></main-component>
  </div>
```

- jsファイルにコンポーネントmain-componentを定義

```js
var Main = {
  template: `<h1>メイン画面</h1>`,
}
var app = new Vue({
  el: '#app',
  components: {
    'start-component': Start,
    'main-component': Main
  }
})
```

これだとボタンを押す前の文字も表示されてしまう。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/621414/134f2b05-6684-cffd-22d9-798f53250571.png)

# 各コンポーネントからvueインスタンスにアクセス


- 公式ドキュメント 特別な問題に対処する  
https://jp.vuejs.org/v2/guide/components-edge-cases.html

ここには以下のような記述がある。

>特別な問題、つまり珍しい状況に対処するためのこのページの全ての機能は、時に Vue のルールを多少なりとも曲げることになります。しかし注意して欲しいのが、それらは全てデメリットや危険な状況をもたらし得るということです。これらのマイナス的な面はそれぞれのケースで注意されているので、このページで紹介されるそれぞれの機能を使用すると決めたときは心に止めておいてください。


それでも前に進む。戦わなければ勝てない。

まずはインスタンスにデータに値を追加する。この`isStartScreen`<strong>を子コンポーネントから</strong>`false`<strong>にすることが目標。</strong>

```js
var app = new Vue({
  el: '#app',
  data: {
    isStartScreen: true
  },
  components: {
    'start-component': Start,
    'main-component': Main
  }
})
```

- `$root`を用いたアクセス

>new Vue インスタンスの全てのサブコンポーネントから、$root プロパティを用いてルートインスタンスへアクセスできます

以下のように`this.$root.isStartScreen`とすることで、<strong>インスタンスの</strong>`isStartScreen`<strong>の値を上書きすることができる。</strong>

```js
var Start = {
  template: `
  <div v-if="this.$root.isStartScreen">
    <h1>スタート画面</h1>
    <button v-on:click="startButton" class="button">start</button>
  </div>`,
  data: function() {
    return {
      isStartScreen: this.$root.isStartScreen
    }
  },
  methods: {
    startButton: function() {
      this.$root.isStartScreen = false;
    }
  }
}
```

ボタンが押された後の画面用コンポーネントの方は、`v-if="!this.$root.isStartScreen"` としておく。つまり、<strong>否定</strong>の論理演算子を用いることで以下のように`isStartScreen`の値は切り替わる。

画面|ボタンが押される前|押された後|
|---|---|---|
スタート画面|true|false|
メイン画面|false|true|

```js
var Main = {
  template: `<h1 v-if="!this.$root.isStartScreen">メイン画面</h1>`,
  data: function() {
    return {
      isStartScreen: this.$root.isStartScreen
    }
  }
}
```

- ボタン押下前

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/621414/22734cd5-263c-cbf6-cbdc-ffd9c30f60b3.png)

- ボタン押下後(スタート画面という文字とボタンがミストディスパージョン)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/621414/b10e2e95-6596-18d9-b4c7-e4bdf08d6ef4.png)



# 参考記事

公式ドキュメント 特別な問題に対処する
https://jp.vuejs.org/v2/guide/components-edge-cases.html