You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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机制,数组索引的修改不会触发响应式更新。

解决方案

有两种可靠的修复方式:

  1. 使用Vue.set触发响应式
    修改cellClicked方法中的赋值语句,同时在组件顶部导入Vue:
// 组件script顶部添加导入
import Vue from 'vue'

// 替换cellClicked里的 this.board[x][y] = this.player;
Vue.set(this.board[x], y, this.player);
  1. 重新赋值数组行
    通过复制并替换整行的方式触发响应式:
// 替换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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.23 15:57:20