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

如何更简洁优雅地用原生JS实现井字棋游戏棋盘的HTML生成

棋盘生成逻辑优化方案

核心优化方向

  • 职责解耦:将渲染逻辑独立封装为BoardRenderer类,和负责业务规则的Board类拆分,后续修改渲染逻辑不会影响核心游戏规则
  • 命名规范化:将语义模糊的x/y单字母变量替换为row/col,变量名遵循JS小驼峰规范,提升可读性
  • 放弃字符串拼接HTML:使用原生DOM API创建元素,避免XSS风险,结构层级更清晰
  • 可配置化设计:支持自定义行类名、格子类名、ID前缀等参数,后续调整样式或交互无需修改底层渲染逻辑
  • 内置交互支持:统一绑定格子点击事件,返回行列坐标,省去后续二次遍历DOM绑定事件的步骤

优化后代码实现

1. 原有Board类(无需修改)

class Board {
    #boardSize;
    #player1Symbol;
    #player2Symbol;

    constructor(boardSize = 3, player1Symbol = 'X', player2Symbol = 'O') {
        this.#boardSize = boardSize;
        this.#player1Symbol = player1Symbol;
        this.#player2Symbol = player2Symbol;
    }

    get boardSize() { return this.#boardSize; }
    get player1Symbol() { return this.#player1Symbol; }
    get player2Symbol() { return this.#player2Symbol; }
}

2. 新增BoardRenderer渲染类

class BoardRenderer {
    constructor(board, containerSelector, options = {}) {
        this.board = board;
        this.container = document.querySelector(containerSelector);
        // 合并默认配置和自定义配置
        this.options = Object.assign({
            rowClassPrefix: 'row-',
            cellClass: 'game-cell',
            cellIdPrefix: 'btn-',
            onCellClick: null
        }, options);
    }

    render() {
        // 清空容器原有内容
        this.container.innerHTML = '';
        const size = this.board.boardSize;

        for (let row = 0; row < size; row++) {
            // 创建行元素
            const rowEl = document.createElement('div');
            rowEl.className = `${this.options.rowClassPrefix}${row}`;

            for (let col = 0; col < size; col++) {
                // 创建格子按钮
                const cellBtn = document.createElement('input');
                cellBtn.type = 'button';
                cellBtn.className = this.options.cellClass;
                cellBtn.id = `${this.options.cellIdPrefix}${row}.${col}`;
                cellBtn.value = ' ';

                // 绑定点击事件
                if (typeof this.options.onCellClick === 'function') {
                    cellBtn.addEventListener('click', () => {
                        this.options.onCellClick(row, col, cellBtn);
                    });
                }

                rowEl.appendChild(cellBtn);
            }

            this.container.appendChild(rowEl);
        }
    }
}

3. 调用示例

// 初始化棋盘实例
const board = new Board(3, 'X', 'O');
// 初始化渲染实例,可传入自定义配置和点击回调
const renderer = new BoardRenderer(board, '.game-ui', {
    cellClass: 'tic-tac-toe-cell',
    onCellClick: (row, col, btn) => {
        console.log(`点击了第${row}行第${col}列的格子`, btn);
        // 这里可以直接写落子逻辑
    }
});
// 执行渲染
renderer.render();

4. HTML代码(无需修改)

<body>
    <div class="game-ui"></div>
</body>

额外优化建议

  • 可以给格子统一加通用类名,比如game-cell,后续写CSS样式不用依赖行类名,选择器更简洁
  • 如果后续要支持自定义棋盘尺寸,只需要修改Board初始化时的参数,渲染逻辑无需调整
  • 可以在BoardRenderer中新增updateCell方法,封装落子后修改按钮内容的逻辑,进一步简化业务代码

内容的提问来源于stack exchange,提问作者Shadow

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.01 03:18:01