React/JS开发星露谷物语布局工具,求可变网格邻接关系识别最优方案
实现方案
核心改造思路:改用二维数组存储网格状态
完全不需要使用复杂的grid-template-area方案,你提到的数学计算方案只要封装得当一点都不冗余,是当前场景最简洁的实现方式:
- 首先将原来的一维方块数组改成二维数组存储,每个维度分别对应行、列,每个元素存储当前方块绑定的作物/道具数据,直接通过
[行索引][列索引]定位对应方块,相邻方块判断逻辑可以封装成通用工具函数,示例如下:// 传入当前坐标,返回上下左右四个方向的有效相邻坐标 const getNeighbors = (row, col, rowTotal, colTotal) => { const directions = [[-1,0], [1,0], [0,-1], [0,1]] return directions.filter(([dr, dc]) => { const newRow = row + dr const newCol = col + dc return newRow >=0 && newRow < rowTotal && newCol >=0 && newCol < colTotal }).map(([dr, dc]) => [row + dr, col + dc]) } - 生成网格的时候直接按行列遍历,给每个CropSquare传入对应的行、列索引,后续所有操作都可以通过行列索引直接定位,不需要靠DOM id或者squareNumber反查位置,修改后的CropGrid示例代码:
function CropGrid(props) { const { numberOfColumns, numberOfRows } = props; // 新增网格状态,存储每个格子的绑定数据,初始为空 const [gridData, setGridData] = useState(() => Array(numberOfRows).fill().map(() => Array(numberOfColumns).fill(null)) ) // 宽高变化时重新初始化网格 useEffect(() => { setGridData(Array(numberOfRows).fill().map(() => Array(numberOfColumns).fill(null))) document.documentElement.style.setProperty('--rows', numberOfRows); document.documentElement.style.setProperty('--columns', numberOfColumns); }, [numberOfColumns, numberOfRows]) // 格子点击回调 const handleSquareClick = (row, col) => { // 这里写选中作物后更新对应格子数据的逻辑 // 批量操作时直接调用getNeighbors遍历连续相同数据的格子即可 } // 生成网格 const cropSquares = [] for(let row = 0; row < numberOfRows; row++) { for(let col = 0; col < numberOfColumns; col++) { cropSquares.push( <CropSquare key={`${row}-${col}`} row={row} col={col} data={gridData[row][col]} onClick={() => handleSquareClick(row, col)} /> ) } } return ( <div id='crop-grid'> {cropSquares} </div> ); } - 连续相同方块批量操作直接用DFS/BFS遍历即可,20*20的网格体量完全不需要考虑性能问题,示例逻辑:
// 从指定坐标出发,找到所有相邻且数据相同的格子坐标 const getSameDataBlocks = (startRow, startCol) => { const targetData = gridData[startRow][startCol] if(targetData === null) return [] const visited = new Set() const result = [] const queue = [[startRow, startCol]] visited.add(`${startRow}-${startCol}`) while(queue.length) { const [row, col] = queue.shift() result.push([row, col]) getNeighbors(row, col, numberOfRows, numberOfColumns).forEach(([nr, nc]) => { const key = `${nr}-${nc}` if(!visited.has(key) && gridData[nr][nc] === targetData) { visited.add(key) queue.push([nr, nc]) } }) } return result }
第三方库说明
你这个场景不需要额外引入第三方库,目前的CSS Grid实现已经完全满足动态尺寸的需求,常见的网格类库都是面向可拖拽、可调整大小的复杂布局场景,引入后反而会增加不必要的包体积和复杂度。
内容的提问来源于stack exchange,提问作者Marty Smith
相关产品推荐
相关产品推荐

