Vue.jsを利用したサイコロアプリ

Image from Gyazo

コンポーネントとは

コンポーネント(Component) とはVue.jsでページを構成する部品のことです. ページの部分的な機能をコンポーネントとして実装することで,ページ内に複数配置したり再利用が可能になります. 今回は サイコロの目 をコンポーネントとして実装し,1から6の目を配置します.

サイコロアプリ

それでは サイコロアプリ を実装して行きましょう. 下記が完成したソースコードです. 「サイコロを振る」というボタンをクリックすると,1から6のいずれかの目が緑色になります.

See the Pen NWxpRYa by Naoto Mukai (@nmukai) on CodePen.

コンポーネントの作成

サイコロの目は divタグで実装します. まずは,divタグをデザインするための CSS を下記のように記述します. pipStylepipFocusの2つのクラスがあり,これをdivタグに適用します.

.pipStyle{
  width: 50px;
  height: 50px;
  border: 1px solid black;
  text-align: center;
  display: table-cell;
  vertical-align: middle;
}

.pipFocus{
  background: #00ff00;
}

div{
  margin: 5px;
}

pip という名前でコンポーネントを実装します. この名前はHTMLでタグ名として用いられます. オプションには propstemplate を設定しています. propspipタグの属性として渡されるデータを指しています. この場合,渡されたデータはflagという変数に格納されます. templateはコンポーネントをHTMLタグとして記述したときの実体であり, ここではサイコロのマス目を表すdiv要素です.

ここで,v-bind:class='{pipFocus: flag}'に注目します. これは,v-bindディレクティブを利用したCSSのクラスの設定を表しており, flagがtrueのときにだけ,pipFocusを有効にすることを意味しています. このようにv-bindディレクティブを用いてCSSの切り替えが可能です.

また,<slot></slot>にも注目しましょう. このslotタグは特別な役割を持ち,pipタグで囲まれた文字列を表します.

Vue.component("pip", {
  props: ["flag"],
  template: "<div class='pipStyle' v-bind:class='{pipFocus: flag}'> <slot></slot> </div>"
})

new Vue({
  el: "#main"
});

コンポーネントを利用してHTMLを記述します. pipタグには,flag属性を設定しています. このflag属性がtrueのときだけ,pipFocusが有効になるため, サイコロの1の目だけが緑色になっていることが確認できます. また,slotタグはpipタグで囲まれた文字列(1または2)に置き換わっています.

<div id="main">

  <div>
    <pip flag="true">1</pip>
    <pip flag="false">2</pip>
  </div>

  <div>
    <button>サイコロを振る</button>
  </div>

</div>

Image from Gyazo

Vueクラスの拡張

次にVueクラスを拡張し,サイコロの状態をデータバインディングで表現することにしましょう. dataオプションで,サイコロの目を表すpips配列と,クラスの有効を切り替えるflags配列を定義しています.

new Vue({
  el: "#main",
  data: {
    pips: ["1", "2", "3", "4", "5", "6"],
    flags: [true, false, false, false, false, false]
  }
});

上記のpips配列とflags属性を利用してHTMLを書き換えます. このとき,v-forディレクティブを利用して,pips要素の数だけpipタグを生成しています. ここで,(pip, i) in pipsはインデックス付きの繰り返しであり,pipには配列の要素,iには配列のインデックスが代入されます.

<div id="main">

  <div>
    <template v-for="(pip, i) in pips">
      <pip v-bind:flag="flags[i]"> {{ pip }} </pip>
    </template>
  </div>

  <div>
    <button>サイコロを振る</button>
  </div>

</div>

Image from Gyazo

rollメソッドの実装

サイコロの目をランダムに決定するrollメソッドを定義します. 配列のインデックスとなる0から5の乱数を生成し, この値に応じてflags配列のtrueの位置を変更します. このとき,Vue.set()メソッドを利用して, 配列に変更があったことを知らせる必要があります(this.flags[i] = true;では動的に変更されない).

new Vue({
  el: "#main",
  data: {
    pips: ["1", "2", "3", "4", "5", "6"],
    flags: [true, false, false, false, false, false]
  },
  methods: {
    roll: function(){

      dice = Math.floor(Math.random() * 6);

      for(i=0; i<this.flags.length; i++){
        if(i == dice){
          Vue.set(this.flags, i, true);
        }
        else{
          Vue.set(this.flags, i, false);
        }
      }
    }
  }
});

最後にv-onディレクティブでrollメソッドを呼び出しましょう. 「サイコロを振る」をクリックすると,緑色の目がランダムに変更されれば完成です.

<div id="main">

  <div>
    <template v-for="(pip, i) in pips">
      <pip v-bind:flag="flags[i]"> {{ pip }} </pip>
    </template>
  </div>

  <div>
    <button v-on:click="roll">サイコロを振る</button>
  </div>

</div>

Image from Gyazo

参考書籍