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


初めに

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

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

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

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

var app = new Vue({
  el: '#app',
  components: {
    'start-component': Start
  }
})
  <div id="app">
    <start-component></start-component>
  </div>

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

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

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


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

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

v-if 召喚

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

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

  1. ボタンを押す
  2. メソッドstartButtonが発動
  3. v-ifの中身がfalseにチェンジ
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追加
  <div id="app">
    <sample-component></sample-component>
    <main-component></main-component>
  </div>
  • jsファイルにコンポーネントmain-componentを定義
var Main = {
  template: `<h1>メイン画面</h1>`,
}
var app = new Vue({
  el: '#app',
  components: {
    'start-component': Start,
    'main-component': Main
  }
})

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

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

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

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

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

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

var app = new Vue({
  el: '#app',
  data: {
    isStartScreen: true
  },
  components: {
    'start-component': Start,
    'main-component': Main
  }
})
  • $rootを用いたアクセス

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

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

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" としておく。つまり、否定の論理演算子を用いることで以下のようにisStartScreenの値は切り替わる。

画面 ボタンが押される前 押された後
スタート画面 true false
メイン画面 false true
var Main = {
  template: `<h1 v-if="!this.$root.isStartScreen">メイン画面</h1>`,
  data: function() {
    return {
      isStartScreen: this.$root.isStartScreen
    }
  }
}
  • ボタン押下前

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

参考記事

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