效果预览
代码实现
<template><div id="app"><div class="mine-sweeper"><div class="board" v-for="row in board" :key="`row-${row.index}`"><divclass="cell":class="{ 'no-clickable': !cell.revealed }"v-for="cell in row.cells":key="`cell-${cell.x}-${cell.y}`"@click="revealCell(cell)"@contextmenu.prevent="flagCell(cell)">{{cell.flagged? '🚩': cell.revealed? cell.isMine? '💣': cell.neighborMines > 0? cell.neighborMines: '': ''}}</div></div></div></div>
</template>
<script>
import { reactive } from 'vue'export default {name: 'App',data () {return {rows: 10,cols: 10,totalMines: 10,board: [],timer: 0}},methods: {startGame () {this.init()this.generateMines()this.calculateNeighborMines()},init () {this.board = reactive(Array.from({ length: this.rows }, (_, rowIndex) => ({index: rowIndex,cells: Array.from({ length: this.cols }, (_, colIndex) => ({x: colIndex,y: rowIndex,isMine: false,revealed: false,flagged: false,neighborMines: 0}))})))},generateMines () {let minesPlaced = 0while (minesPlaced < this.totalMines) {const row = Math.floor(Math.random() * this.rows)const col = Math.floor(Math.random() * this.cols)if (!this.board[row].cells[col].isMine) {this.board[row].cells[col].isMine = trueminesPlaced++}}},calculateNeighborMines () {for (let row = 0; row < this.rows; row++) {for (let col = 0; col < this.cols; col++) {if (!this.board[row].cells[col].isMine) {let neighborMines = 0for (let i = -1; i <= 1; i++) {for (let j = -1; j <= 1; j++) {const newRow = row + iconst newCol = col + jif (newRow >= 0 && newRow < this.rows && newCol >= 0 && newCol < this.board[row].cells.length && this.board[newRow].cells[newCol].isMine) {neighborMines++}}}this.board[row].cells[col].neighborMines = neighborMines}}}},revealCell (cell) {if (!cell.revealed && !cell.flagged) {cell.revealed = trueif (cell.isMine) {setTimeout(() => {alert('Game Over!')this.startGame()}, 100)return}if (this.board.every(row => row.cells.every(cell => cell.revealed || cell.isMine))) {setTimeout(() => {alert('You Win!')this.startGame()}, 100)}if (cell.neighborMines === 0) {for (let i = -1; i <= 1; i++) {for (let j = -1; j <= 1; j++) {const newRow = cell.y + iconst newCol = cell.x + jif (newRow >= 0 && newRow < this.rows && newCol >= 0 && newCol < this.board[newRow].cells.length) {const neighborCell = this.board[newRow].cells[newCol]if (!neighborCell.revealed && !neighborCell.flagged) {this.revealCell(neighborCell)}}}}}}},flagCell (cell) {if (cell.revealed) {return}cell.flagged = !cell.flagged}},mounted () {this.startGame()}
};
</script>
<style scoped>
.mine-sweeper {display: flex;justify-content: center;align-items: center;
}
.board {display: flex;flex-direction: column;
}
.cell {width: 50px;height: 50px;border: 1px solid #ccc;display: flex;justify-content: center;align-items: center;
}
.no-clickable {background: gray;
}
</style>