嵌套井字棋:点击单元格无法在对应位置生成X/O的问题
解决嵌套井字棋点击单元格生成X/O的问题
问题根源
- 选错目标单元格:
document.querySelector(".cell")只会匹配页面中第一个.cell元素,不管点击哪个格子,SVG都往第一个单元格里加。 - 未传递点击目标:
play()函数不知道当前点击的是哪个单元格,无法对应操作目标。 - 未检查单元格状态:重复点击同一单元格会不断叠加X/O,不符合游戏规则。
- 逻辑顺序错误:else分支里
turn = "x"写在return之后,永远不会执行,导致一直生成O。
修复方案
- 给
play函数传递点击目标:将单元格的onclick改为onclick="play(this)",让函数获取当前点击的单元格元素。 - 增加单元格占用检查:判断单元格内是否已有子元素,有则直接返回,避免重复生成。
- 修正目标元素操作:直接使用传入的单元格元素进行操作,不再用
querySelector查找第一个匹配项。 - 调整else分支代码顺序:将
turn = "x"放在return之前,确保回合切换生效。
修改后的完整代码
function create_elements_from_html(n, html){ const template = document.createElement("template") let htmlaux = `` // 声明循环变量a,避免全局污染 for (let a = 0; a < n; a += 1){ htmlaux += html } template.innerHTML = htmlaux return template.content; } let turn = "x" // 接收当前点击的单元格作为参数 function play(cell){ // 检查单元格是否已被占用,有内容则直接返回 if (cell.children.length > 0) return; let svgContent; if (turn === "x"){ svgContent = create_elements_from_html(1, `<svg viewBox="0 0 100 100"> <path class="x_cell_path" d="M 10 10 L 90 90 Z M 10 90 L 90 10"> </svg>`) turn = "o" } else { svgContent = create_elements_from_html(1, `<svg viewBox="0 0 100 100"> <circle class="o_cell_path" r="40" cx="50" cy="50"> </svg>`) turn = "x" } // 将SVG添加到当前点击的单元格中 cell.appendChild(svgContent) } let big_board = create_elements_from_html(1, `<div class="big_board"> <svg class="small_board_svg" viewBox="0 0 100 100"> <path class="big_board_path" d="M 33.33333 0 l 0 100 M 66.66666 0 l 0 100 M 0 33.33333 l 100 0 M 0 66.66666 l 100 0"> </svg> </div>`) document.body.appendChild(big_board) let small_board = create_elements_from_html(9, `<div class="small_board"> <svg class="small_board_svg" viewBox="0 0 100 100"> <path class="small_board_path" d="M 33.33333 0 l 0 100 M 66.66666 0 l 0 100 M 0 33.33333 l 100 0 M 0 66.66666 l 100 0"> </svg> </div>`) document.querySelector(".big_board").appendChild(small_board) for (let i = 0; i < 9; i++) { let cell = create_elements_from_html(1, ` <div class="cell" data-cell onclick="play(this)"> </div>`) document.querySelectorAll(".small_board").forEach((board) => board.appendChild(cell.cloneNode(true))) }
额外优化
- 给循环变量
a添加let声明,避免全局变量污染。 - 合并SVG生成逻辑,减少重复代码。
内容的提问来源于stack exchange,提问作者Pudimedo
相关产品推荐
相关产品推荐

