img

Vue井字棋游戏

2020-07-02 0条评论 2.3k次阅读 JavaScript


效果:

1.gif

源码:

<!DOCTYPE html>
<html lang="en">

<head>
   <meta charset="UTF-8">
   <meta name="viewport" content="width=device-width, initial-scale=1.0">
   <title>Document</title>
   <style>
      body {
         font: 14px "Century Gothic", Futura, sans-serif;
         margin: 20px;
      }

      ol,
      ul {
         padding-left: 30px;
      }

      .board-row:after {
         clear: both;
         content: "";
         display: table;
      }

      .status {
         margin-bottom: 10px;
      }

      .square {
         background: #fff;
         border: 1px solid #999;
         float: left;
         font-size: 100px;
         font-weight: 700;
         line-height: 100px;
         height: 100px;
         margin-right: -1px;
         margin-top: -1px;
         padding: 0;
         text-align: center;
         width: 100px;
      }

      .square:focus {
         outline: none;
      }

      .kbd-navigation .square:focus {
         background: #ddd;
      }

      .game-info {
         margin-top: 20px;
      }
   </style>
   <script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.1.6/vue.min.js"></script>
</head>

<body>
<div id="app">
   <Game></Game>
</div>

<template id="tplSquare">
   <button class="square" @click="$emit('click')">{{id}}</button>
</template>

<template id="tplBoard">
   <div class="row">
      <div class="board-row" v-for="row in [[0,1,2],[3,4,5],[6,7,8]]">
         <Square v-for="i in row" :id="squares[i]" @click="$emit('click', i)" />
      </div>
   </div>
</template>

<template id="tplGame">
   <div class="game">
      <div class="game-board">
         <Board @click="click" :squares="history[stepNumber].squares" />
      </div>
      <div class="game-info">
         <div v-if="winner">Winner: {{winner}}</div>
         <div v-if="!winner">Next player: {{xIsNext ? "X" : "O"}}</div>
         <ol>
            <li v-for="(h,move) in history">
               <button @click="jumpTo(move)">{{move?"Go to move #"+move:"Go to game start"}}</button>
            </li>
         </ol>
      </div>
   </div>
</template>

<script>
   Vue.component('Square', {
      props: { id: null },
      // template: `<button class="square" @click="$emit('click')">{{id}}</button>`,
      template: "#tplSquare"
   })

   Vue.component('Board', {
      props: { squares: [] },
      template: "#tplBoard"
   })

   Vue.component('Game', {
      data() {
         return {
            history: [{ squares: Array(9).fill(null) }],
            stepNumber: 0,
            xIsNext: true,
            status: "",
            winner: "",
         }
      },
      methods: {
         jumpTo(step) {
            this.stepNumber = step
            this.xIsNext = (step % 2) === 0
         },
         calculateWinner(squares) {
            const lines = [
               [0, 1, 2], [3, 4, 5], [6, 7, 8],
               [0, 3, 6], [1, 4, 7], [2, 5, 8],
               [0, 4, 8], [2, 4, 6],
            ];
            for (let i = 0; i < lines.length; i++) {
               const [a, b, c] = lines[i];
               if (squares[a] && squares[a] === squares[b] && squares[a] === squares[c]) {
                  return squares[a];
               }
            }
            return null;
         },
         click(id) {
            const history = this.history.slice(0, this.stepNumber + 1)
            const current = history[history.length - 1]
            const squares = current.squares.slice()
            this.winner = this.calculateWinner(squares)
            if (this.winner || squares[id]) return

            squares[id] = this.xIsNext ? "X" : "O"
            this.history = history.concat([{ squares: squares }])
            this.stepNumber = history.length
            this.xIsNext = !this.xIsNext
            this.winner = this.calculateWinner(squares)
         }
      },
      template: "#tplGame"
   })

   new Vue({ el: '#app' })
</script>
</body>

</html>

💬 COMMENT


🦄 支持markdown语法

👋友