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

基于动态Div棋盘实现FEN字符串到棋子布局的转换

问题解决:FEN生成国际象棋棋盘时classList未定义错误

错误原因分析

  1. 变量冲突+元素查找失效:外层循环用i生成从1开始的格子ID,但内层循环又用let i = 0遍历FEN字符串,导致document.getElementById(i)查找的是ID为0、1...的元素——而实际生成的格子ID是1~64,ID为0的元素不存在,el为null,调用classList自然报错。
  2. FEN字符串处理逻辑错误:直接遍历FEN字符是错误的——FEN中的数字代表连续的空格子(比如8表示8个无棋子的格子),不是单个字符对应单个格子。
  3. 逻辑顺序混乱:每次生成一个格子就遍历整个FEN重复处理,既低效又容易引发未渲染完成的问题。

修复后的实现方案

核心思路:先把FEN解析成8x8的棋子数组,再逐个生成棋盘格子,同时直接给对应格子添加棋子类名,避免事后通过ID查找元素的问题。

class Grid {
    constructor(length, height) {
        this.length = length;
        this.height = height;
    }

    // 解析FEN字符串,转换成8x8的棋子数组(空格子用''表示)
    parseFen(fen) {
        const boardArray = [];
        // 只取FEN的棋盘部分,忽略回合等后续信息
        const fenBoard = fen.split(' ')[0];
        const rows = fenBoard.split('/');
        
        for (const row of rows) {
            const rowCells = [];
            for (const char of row) {
                if (!isNaN(char)) {
                    // 数字代表n个空格子
                    for (let i = 0; i < parseInt(char); i++) {
                        rowCells.push('');
                    }
                } else {
                    rowCells.push(char);
                }
            }
            boardArray.push(rowCells);
        }
        return boardArray;
    }

    render(fen) {
        const boardElement = document.getElementById('board');
        // 清空棋盘容器,避免重复渲染叠加
        boardElement.innerHTML = '';
        const boardArray = this.parseFen(fen);
        
        let cellId = 1;
        for (let row = 0; row < this.height; row++) {
            for (let col = 0; col < this.length; col++) {
                const isWhiteSquare = (row + col) % 2 === 0;
                const square = document.createElement('div');
                square.style.cssText = `height:100px;width:100px;background-color:${isWhiteSquare ? '#ff9c9c' : '#fa6666'};display:inline-block;padding:0;`;
                square.id = `${cellId}`;
                square.className = isWhiteSquare ? 'ws' : 'bs';

                // 根据解析后的数组添加棋子类名
                const piece = boardArray[row][col];
                switch (piece) {
                    case 'p': square.classList.add('bpawn'); break;
                    case 'r': square.classList.add('brook'); break;
                    case 'n': square.classList.add('bknight'); break;
                    case 'b': square.classList.add('bbishop'); break;
                    case 'q': square.classList.add('bqueen'); break;
                    case 'k': square.classList.add('bking'); break;
                    case 'P': square.classList.add('wpawn'); break;
                    case 'R': square.classList.add('wrook'); break;
                    case 'N': square.classList.add('wknight'); break;
                    case 'B': square.classList.add('wbishop'); break;
                    case 'Q': square.classList.add('wqueen'); break;
                    case 'K': square.classList.add('wking'); break;
                }

                boardElement.appendChild(square);
                cellId++;
            }
            // 每行结束添加换行
            boardElement.appendChild(document.createElement('br'));
        }
    }
}

// 实例化并渲染
let board = new Grid(8, 8);
board.render('rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR');

关键优化点

  • FEN解析逻辑:单独提取parseFen方法处理字符串,正确解析数字代表的空格子,生成标准的8x8数组。
  • 直接操作元素:生成格子时直接根据解析结果添加类名,无需事后通过ID查找元素,彻底避免“元素未找到”的问题。
  • 变量规范:避免循环变量重名,逻辑更清晰。
  • 容器清空:渲染前清空容器,防止重复调用render时叠加内容。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.30 13:18:08