
本文详解如何在基于 css grid 的像素画板中,使用原生 javascript 实现可靠的 flood fill 功能——通过递归深度优先搜索(dfs)遍历连通区域,精准替换相同背景色的相邻格子,兼顾可读性与实际可用性。
本文详解如何在基于 css grid 的像素画板中,使用原生 javascript 实现可靠的 flood fill 功能——通过递归深度优先搜索(dfs)遍历连通区域,精准替换相同背景色的相邻格子,兼顾可读性与实际可用性。
Flood Fill 是像素编辑器中的核心功能之一,其目标是:当用户点击某个格子时,将所有与该格子连通且颜色相同的相邻格子,统一填充为新选颜色。在你当前的网格结构中,.pixel-grid 是一个动态生成的 CSS Grid 容器,其子元素 .grid-item 按行优先顺序排列(即第 0 行从左到右,接着第 1 行……),这为基于索引的邻域计算提供了坚实基础。
以下是经过优化、健壮性增强的 floodFill 实现(已适配你的 DOM 结构与变量命名):
function floodFill(element) {
// 1. 获取被点击的格子及其父容器
const clickedItem = element;
if (!clickedItem || !clickedItem.classList.contains('grid-item')) return;
const gridContainer = clickedItem.parentNode;
const gridItems = Array.from(gridContainer.children); // 转为数组便于索引操作
const clickedIndex = gridItems.indexOf(clickedItem);
// 2. 计算网格维度
const selectedValue = myRange[indexRangeInput.value]; // 当前网格边长(如 8×8)
const itemsPerRow = selectedValue;
// 3. 获取原始颜色(注意:需处理空值或 transparent 情况)
const originalColor = clickedItem.style.backgroundColor || 'white';
// 4. 边界与终止条件检查(避免重复填充/栈溢出)
if (originalColor === selectedColor) return; // 目标色与原色相同,直接退出
// 5. 核心递归函数(DFS)
function dfs(index) {
// 越界检查
if (index < 0 || index >= gridItems.length) return;
const current = gridItems[index];
const currentColor = current.style.backgroundColor || 'white';
// 颜色不匹配 → 终止递归分支
if (currentColor !== originalColor) return;
// 填充当前格子
current.style.backgroundColor = selectedColor;
// 向四个正交方向递归(上、下、左、右)
// 注意:需防止跨行误连(如最右列向右会跳到下一行首列,故需额外行列校验)
const row = Math.floor(index / itemsPerRow);
const col = index % itemsPerRow;
// 上:同一列,上一行
if (row > 0) dfs(index - itemsPerRow);
// 下:同一列,下一行
if (row < itemsPerRow - 1) dfs(index + itemsPerRow);
// 左:同一行,前一列(需防跨行)
if (col > 0) dfs(index - 1);
// 右:同一行,后一列(需防跨行)
if (col < itemsPerRow - 1) dfs(index + 1);
}
// 启动填充
dfs(clickedIndex);
}✅ 关键设计说明:
- 索引映射准确:利用 Array.from().indexOf() 获取点击格子在线性数组中的位置,并通过 Math.floor(index / itemsPerRow) 和 index % itemsPerRow 还原行列坐标,确保上下左右移动不越界或跨行错误。
- 空背景兼容:|| 'white' 处理未显式设置 backgroundColor 的格子(默认为白色),避免 '' === originalColor 判定失效。
- 提前终止优化:首行检查 originalColor === selectedColor,杜绝无意义递归,防止栈溢出或性能浪费。
- 方向安全校验:每个方向移动前均验证行列有效性(如 row > 0、col < itemsPerRow - 1),比单纯 isValidIndex 更精准,彻底规避对角线“穿墙”问题。
⚠️ 注意事项:
- 递归深度风险:对于大网格(如 64×64),极端情况下可能触发浏览器调用栈限制。生产环境建议改用迭代版 BFS(借助 Array 模拟队列),代码更长但绝对安全。
- 颜色匹配局限:当前依赖 style.backgroundColor 字符串全等匹配(如 "rgb(0, 0, 0)" === "rgb(0, 0, 0)")。若需支持 #000、black 等等效色,应引入标准化颜色解析函数(如转为十六进制或 HSL 统一比较)。
- 事件绑定时机:确保 floodFill 仅在 isFillSelected 为 true 且 mousedown 触发时调用,避免与画笔逻辑冲突——你现有的事件监听结构已正确隔离。
至此,你的像素画板已具备专业级 Flood Fill 能力。只需将上述函数替换原 JS 中的空 floodFill 占位符,即可立即生效。后续可进一步扩展为 8 方向填充、抗锯齿边缘检测,或集成撤销栈以支持历史回退——坚实的基础,始于一次精准的递归遍历。

















