基于动态Div棋盘实现FEN字符串到棋子布局的转换
问题解决:FEN生成国际象棋棋盘时classList未定义错误
错误原因分析
- 变量冲突+元素查找失效:外层循环用
i生成从1开始的格子ID,但内层循环又用let i = 0遍历FEN字符串,导致document.getElementById(i)查找的是ID为0、1...的元素——而实际生成的格子ID是1~64,ID为0的元素不存在,el为null,调用classList自然报错。 - FEN字符串处理逻辑错误:直接遍历FEN字符是错误的——FEN中的数字代表连续的空格子(比如
8表示8个无棋子的格子),不是单个字符对应单个格子。 - 逻辑顺序混乱:每次生成一个格子就遍历整个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
相关产品推荐
相关产品推荐

