概要

React 公式のチュートリアルで紹介されている三目並べゲームを Vue.js で作ってみます。

スターターコードを用意する

チュートリアルではスターターコードが用意されています。
そこには既に 3 つのコンポーネントが作られています。

  • Square
  • Board
  • Game

まずはこれらのコンポーネントを作りましょう。

// app.js
Vue.component("Square", {
  template: '<button class="square">{{ /* TODO */ }}</button>',
});

Vue.component("Board", {
  data() {
    return { status: "Next player: X" };
  },
  template: `
  <div>
    <div class="status">{{ status }}</div>
    <div class="board-row">
      <Square :value="0" />
      <Square :value="1" />
      <Square :value="2" />
    </div>
    <div class="board-row">
      <Square :value="3" />
      <Square :value="4" />
      <Square :value="5" />
    </div>
    <div class="board-row">
      <Square :value="6" />
      <Square :value="7" />
      <Square :value="8" />
    </div>
  </div>`,
});

Vue.component("Game", {
  template: `
    <div class="game">
      <div>
        <Board />
      </div>
      <div class="game-info">
        <div>{{ /* status */ }}</div>
        <ol>{{ /* TODO */ }}</ol>
      </div>
    </div>
    `,
});

const app = new Vue({
  el: "#app",
});
<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>TicTacToe</title>
    <link rel="stylesheet" href="style.css" />
  </head>
  <body>
    <div id="app">
      <Game />
    </div>
  </body>
  <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
  <script src="app.js"></script>
</html>

データを Props を使って渡す

ここからチュートリアル通りやっていきます。

Board から Square へ value プロパティ を props 経由で渡すようコードを変更します。

ここではすでに Board の方では v-bind で値を渡しているので変更の必要はありません。
Square のテンプレートで props を定義し、受け取った値を表示するように書き換えます。

Vue.component("Square", {
  props: ["value"],
  template: '<button class="square">{{ value }}</button>',
});

9 つのマスに 0 から 8 までの数字が入っていることが確認できます。

イベントハンドラを付け加える

Square コンポーネントがクリックされると、数字のかわりに “X” と表示されるように変更します。
これには Square のボタンタグにイベントハンドラを設定します。

Vue.component("Square", {
  props: ["value"],
  methods: {
    click() {
      alert("click");
    },
  },
  template: '<button class="square" @click="click">{{ value }}</button>',
});

こちらではチュートリアルのようにエラーは出ません。
そのかわり、テンプレートでは直接 alert 関数を呼び出せないため、methods プロパティで click 関数を定義しています。

次に、クリックされたマスが “X” で埋められるように変更します。

Square コンポーネントに状態を持たせるため、data に value プロパティを追加します。
そして クリックされたときに value プロパティに “X” がセットされるようにします。

Vue.component("Square", {
  data() {
    return { value: null };
  },
  methods: {
    click() {
      this.value = "X";
    },
  },
  template: '<button class="square" @click="click">{{ value }}</button>',
});

ここまでで、基本的な部分が完成です。
次はターン制や勝敗判定をできるようにしていきます。