Vue2二维数组更新后DOM不刷新:井字棋点击无显示问题
井字棋游戏DOM更新问题求助
我开发了一个井字棋(TicTacToe)游戏,但点击单元格时,DOM无法更新显示正确的X或O值。我认为这是由于board为二维数组导致的,尝试了以下代码仍无效:
{{ cell === 'X' ? 'close' : cell === 'O' ? 'circle' : '' }}
求解决点击单元格后显示对应X或O值的方法?
更新:完整代码
App.vue
<template> <div id="app"> <TicTacToe /> </div> </template> <script> import TicTacToe from "./components/TicTacToe.vue"; export default { name: "App", components: { TicTacToe }, }; </script> <style> #app { font-family: Avenir, Helvetica, Arial, sans-serif; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; text-align: center; color: #2c3e50; margin-top: 60px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; } </style>
TicTacToe.vue
<template> <div class="tic-tac-toe"> <div class="row" v-for="(row, x) in board" :key="x"> <div class="cell" v-for="(cell, y) in row" :key="y" @click="cellClicked(x, y)" > {{ cell }} </div> </div> </div> </template> <script> export default { data() { return { player: "X", winner: null, board: [ ["", "", ""], ["", "", ""], ["", "", ""], ], }; }, methods: { winningCondition(board) { const condition = [ [0, 1, 2], [3, 4, 5], [6, 7, 8], [0, 4, 8], [1, 4, 7], [2, 4, 6], [0, 3, 6], [2, 5, 8], ]; for (let i = 0; i < condition.length; i++) { const [a, b, c] = condition[i]; if (board[a] && board[a] === board[b] && board[a] === board[c]) { return (this.winner = board[a]); } } return (this.winner = null); }, cellClicked(x, y) { if (this.winner) return; if (this.board[x][y]) return; this.board[x][y] = this.player; this.player = this.player === "X" ? "O" : "X"; this.winningCondition(this.board.flat()); }, }, }; </script> <style scoped> .cell { border: solid black 1px; width: 42px; height: 42px; align-items: center; display: flex; justify-content: center; } .row { display: flex; flex-direction: row; } .tic-tac-toe { display: flex; flex-wrap: wrap; flex-direction: column; } </style>
问题原因与解决方案
原因
Vue 2的响应式系统无法检测数组中元素的直接赋值操作(比如this.board[x][y] = this.player),因为它依赖对象属性的getter/setter机制,数组索引的修改不会触发响应式更新。
解决方案
有两种可靠的修复方式:
- 使用
Vue.set触发响应式
修改cellClicked方法中的赋值语句,同时在组件顶部导入Vue:
// 组件script顶部添加导入 import Vue from 'vue' // 替换cellClicked里的 this.board[x][y] = this.player; Vue.set(this.board[x], y, this.player);
- 重新赋值数组行
通过复制并替换整行的方式触发响应式:
// 替换cellClicked里的 this.board[x][y] = this.player; const updatedRow = [...this.board[x]]; updatedRow[y] = this.player; this.board.splice(x, 1, updatedRow);
两种方法都能让Vue感知到board的变化,从而更新DOM显示正确的X或O。
内容的提问来源于stack exchange,提问作者seyet
相关产品推荐
相关产品推荐

