LogicFlow `grid: false` 简写失效 Bug 修复解析:从 `assign` 合并陷阱到构造函数最小修复
LogicFlowgrid: false简写失效 Bug 修复解析从assign合并陷阱到构造函数最小修复【免费下载链接】LogicFlowA flow chart editing framework focus on business customization. 专注于业务自定义的流程图编辑框架支持实现脑图、ER图、UML、工作流等各种图编辑场景。项目地址: https://gitcode.com/GitHub_Trending/lo/LogicFlow导读本文围绕 LogicFlow 核心包logicflow/core在 2.2.1 版本中引入的网格配置简写失效问题展开当用户在构造函数中传入grid: false/grid: true/grid: 20这类布尔或数字简写时由于GraphModel构造函数统一走assign({}, initialGrid, grid)合并路径简写值无法拷贝任何属性导致用户配置被忽略、画布始终显示默认网格。本文以 2026-06-30-grid-false-assign-bug-design.md 设计文档为主线结合GraphModel、Grid.getGridOptions、gridModeMap等源码与测试用例完整还原 Bug 成因、修复决策、目标行为矩阵、最小实现方案与验证方法帮助读者理解 LogicFlow 网格解析的底层语义并掌握可复用的「简写配置回归」修复思路。背景2.2.1 引入的assign合并路径自logicflow/core2.2.1起GraphModel构造函数将grid选项通过assign({}, initialGrid, grid)合并后再传给Grid.getGridOptions。问题在于当grid是布尔值或数字时assign这类浅合并函数无法拷贝任何属性——布尔和数字没有可枚举的自身属性合并结果等价于仅含initialGrid于是用户传入的grid: false/grid: true/grid: 20全部被忽略最终始终使用gridModeMap中的defaultGrid其visible: true。也就是说2.2.1 之前2.1.9 ~ 2.1.11使用的是Grid.getGridOptions(grid ?? false)行为正确2.2.1 的这次主题网格合并改造意外破坏了简写语义属于典型的合并函数误用布尔/数字入参导致的回归。文档约定的网格语义设计文档援引了 grid 教程 与 LogicFlow.Options 中约定的四种写法写法语义默认 /grid: false画布不显示网格线默认值即为falsegrid: true开启默认网格grid: number设置网格间距grid: { ... }细粒度配置size、visible、type、config等在 options.ts 中grid的类型被定义为number | boolean | GridOptions且默认值grid: false见 options.ts与文档约定完全一致。因此修复的目标就是恢复简写值直接交由getGridOptions内部类型分支处理的 2.1.x 语义。根因分析assign无法合并非对象值在 GraphModel.ts 中修复后的构造函数关键代码如下this.grid Grid.getGridOptions( typeof grid object grid ! null ? assign({}, initialGrid, grid) : (grid ?? false), )理解这个分支的前提是看透旧代码的问题。旧写法this.grid Grid.getGridOptions(assign({}, initialGrid, grid))当grid为false时assign({}, initialGrid, false)等价于initialGriddefaultGrid其visible: true于是本应隐藏的网格线被显示当grid为true或20时同样无法把visible/size覆盖上去。assign的正确用法对象合并不是问题问题出在没有先做类型判断就把任意值丢给了对象合并。修复后的逻辑清晰分叉对象typeof grid object grid ! null保留 2.2 的主题网格合并能力即initialGrid来自gridModeMap[themeMode]与用户对象做浅合并让对象写法继续享有主题默认样式布尔 / 数字 /undefined直接交给getGridOptions由函数内部的类型分支统一处理与 2.1.x 行为一致undefined经?? false归一为false与Options.defaults.grid保持一致。值得注意分支特意排除了null——typeof null object是 JavaScript 的经典坑若不显式排除grid: null会误入对象合并路径。getGridOptions的内部类型分支设计文档明确不修改Grid.getGridOptions本身因为该函数已经具备完善的类型分支。见 Grid.tsxexport function getGridOptions(options: number | boolean | GridOptions) { const defaultOptions cloneDeep(defaultGrid) as GridOptions if (typeof options number) { return assign(defaultOptions, { size: options }) } else if (typeof options boolean) { return assign(defaultOptions, { visible: options }) } else { return assign(defaultOptions, options) } }三种入参的处理策略一目了然数字以defaultGrid为基础仅覆盖sizevisible保持defaultGrid的true布尔以defaultGrid为基础仅覆盖visible对象整体浅合并。由于defaultGrid的定义见 theme.ts是visible: true、type: mesh、size: DEFAULT_GRID_SIZEDEFAULT_GRID_SIZE 10见 theme.ts所以grid: true解析出的网格类型必然是mesh而非dot——这正是通用defaultGrid而非主题网格的关键差异点。决策记录三个关键取舍设计文档给出了三行决策记录明确了修复边界问题决策grid: true的样式来源A通用defaultGrid与 2.1.x 一致。仅对象形式grid: { ... }或与themeMode相关的setTheme({ grid })才合并gridModeMap[themeMode]修复范围最小 bugfix仅修构造函数初始化路径setTheme(_, themeMode)切换主题时覆盖grid: false本次不修作为已知限制记录若后续需要再单独立项决策 A 的含义是布尔/数字简写与主题网格解耦。传入grid: true时即使当前themeMode是dark或retro也一律使用通用defaultGridmesh类型、#D7DEEB颜色不再跟随主题的gridModeMap。只有对象写法grid: { ... }才会先与gridModeMap[themeMode]合并从而继承主题网格样式。第三个决策是已知限制而非缺陷setTheme切换themeMode时GraphModel.ts 会执行Grid.getGridOptions({ ...this.grid, ...gridModeMap[themeMode] })用主题网格覆盖用户显式设置的grid: false。这一覆盖路径不在本次最小修复范围内被记录为已知限制留待单独立项处理。目标行为矩阵修复后的预期语义设计文档给出了完整的输入—输出对照表这是验证修复正确性的行为规格输入期望结果未传 /grid: falsevisible: false不显示网格线gridSize保持默认 1grid: truegetGridOptions(true)→defaultGridvisible: true不使用gridModeMap主题网格grid: 20getGridOptions(20)→defaultGridsize: 20visible: truegrid: { visible: false }合并initialGrid后visible: false对象形式可走主题默认样式但隐藏网格线grid: { size: 20, type: dot }合并initialGrid主题网格与用户对象再经getGridOptions规范化注意第一行中gridSize保持默认 1 的前提gridSize仅在snapGrid: true时才会被赋值为解析后的grid.size见 GraphModel.tsif (options.snapGrid) { // 开启网格对齐时以解析后的 grid.size 作为吸附步长兼容 number/boolean/object 三种简写 this.gridSize this.grid.size || 1 }这意味着grid: false但snapGrid: true时网格线虽不显示吸附步长仍以gridSize生效——隐藏网格线但保留网格对齐效果这与 grid 教程 中对visible: false的描述一致。实现方案最小修复与范围边界修改点文件packages/core/src/model/GraphModel.ts构造函数修改前this.grid Grid.getGridOptions(assign({}, initialGrid, grid))修改后this.grid Grid.getGridOptions( typeof grid object grid ! null ? assign({}, initialGrid, grid) : (grid ?? false), )设计文档强调本次不修改Grid.getGridOptions本身也不新增 helper 函数——单行分支足够清晰。这体现了最小 bugfix 原则只收窄构造函数的分支逻辑对象形式路径完全不变将回归风险压缩到最低。不在本次范围设计文档明确列出四项不在本次范围内的事项setTheme(style, themeMode)切换themeMode时gridModeMap合并可能覆盖用户显式grid: false即上述已知限制对应 GraphModel.tsbackground: false与assign({}, initialBackground, background)的类似模式——但该处已有if (background)守卫见 GraphModel.ts行为不同不受影响文档更新本次是恢复既有约定而非行为变更无需改文档examples/dynamic-group-regression中已有的grid: false写法可原样保留修复后无需改写为对象形式。最后一点很关键回归示例仓库里大量使用grid: false修复后它们将自然恢复正确行为不需要任何迁移工作。测试验证独立实例 独立 DOM 容器设计文档建议在packages/core/__tests__/model/graphmodel.test.ts或新建grid-options.test.ts中增加用例并特别强调每个用例使用独立LogicFlow实例与独立 DOM 容器避免与既有grid: true的全局 fixture 冲突。仓库中已存在 grid-options.test.ts其测试设计与设计文档的用例清单高度吻合grid: false→visible false见 grid-options.test.tsgrid: true在非默认themeMode: dark下仍使用通用defaultGridtype mesh、config.color #D7DEEB见 grid-options.test.ts——这正是设计文档grid: true不使用主题网格决策的直接证据grid: 20在themeMode: dark下size 20且visible true见 grid-options.test.ts对象形式先合并主题默认值再应用用户覆盖grid: { visible: false, size: 30 }在themeMode: retro下结果为visible: false、size: 30、type: dot、config.color #ababab见 grid-options.test.ts——retro主题的网格默认值恰好是dot类型、#ababab颜色见 theme.ts验证了对象写法确实先与主题网格合并。此外测试还覆盖了snapGrid与grid.size的联动grid: 20snapGrid: true时gridSize为 20grid: truesnapGrid: true时gridSize为 10defaultGrid.size而snapGrid: false时gridSize保持 1。运行验证命令设计文档给出的验证命令如下cd packages/core pnpm test -- graphmodel # 或 pnpm test -- grid第一条聚焦于graphmodel相关的既有测试第二条则可通过测试名过滤-- grid单独运行上述网格选项用例。发布说明与风险发布说明设计文档要求同步在 packages/core/CHANGELOG.md 增加Fixed条目修复grid: false/grid: true/grid: number简写在 2.2.1 失效、始终显示默认网格的问题风险与兼容性设计文档评估整体风险为低依据如下仅收窄了构造函数分支对象形式路径assign({}, initialGrid, grid)完全不变对象写法的用户不受任何影响唯一的语义变化依赖「grid: true始终显示主题网格」的 2.2.1 用户如果存在的话修复后将恢复为通用defaultGrid。但这与官方文档及 2.1.x 行为完全一致属于回归修复而非新行为可接受。换句话说本次修复是在「恢复文档约定」与「修正 2.2.1 回归」之间取最大公约数对绝大多数用户而言是无感且正确的。延伸理解setTheme中的网格处理虽然setTheme的主题切换覆盖不在本次修复范围但理解它的行为有助于全面掌握 LogicFlow 网格机制。见 GraphModel.tsaction setTheme( style: PartialLogicFlow.Theme, themeMode?: LogicFlow.ThemeMode | string, ) { if (themeMode) { this.themeMode themeMode // 修改背景颜色 backgroundModeMap[themeMode] this.updateBackgroundOptions({ ...(typeof this.background object ? this.background : {}), ...backgroundModeMap[themeMode], }) gridModeMap[themeMode] this.updateGridOptions( Grid.getGridOptions({ ...this.grid, ...gridModeMap[themeMode] }), ) } if (style.background) { this.updateBackgroundOptions(style.background) } if (style.grid) { const formattedGrid Grid.getGridOptions(style.grid ?? false) this.updateGridOptions(formattedGrid) } this.theme updateTheme({ ...this.customStyles, ...style }, themeMode) this.customStyles { ...this.customStyles, ...style } }两个要点themeMode切换路径会执行Grid.getGridOptions({ ...this.grid, ...gridModeMap[themeMode] })——注意这里把当前this.grid与目标主题网格做对象合并主题网格属性会覆盖用户设置这正是设计文档记录的已知限制来源而style.grid路径则直接走Grid.getGridOptions(style.grid ?? false)——与构造函数修复后的简写处理保持一致说明修复方案的设计思路在setTheme中已有先例?? false的归一写法并非凭空引入。在 theme.ts 中还可看到gridModeMap[themeMode] style.grid || defaultGrid的动态注册机制配合 theme.ts 中预置的colorful、dark、retro、default四套网格共同构成 LogicFlow 主题网格体系的底层。小结grid: false简写失效 Bug 的修复是一个教科书式的最小回归修复案例根因是assign浅合并被错误地用于布尔/数字入参修复手段是在构造函数中增加一行类型分支——对象走主题合并其余简写直接交还getGridOptions的类型分支处理并配合独立的grid-options.test.ts用例锁定五种输入的行为规格。整个修复不触碰getGridOptions、不新增 helper、不改文档将风险压缩到仅收窄构造函数分支的单一改动点最终恢复了与官方文档及 2.1.x 完全一致的网格语义。【免费下载链接】LogicFlowA flow chart editing framework focus on business customization. 专注于业务自定义的流程图编辑框架支持实现脑图、ER图、UML、工作流等各种图编辑场景。项目地址: https://gitcode.com/GitHub_Trending/lo/LogicFlow创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考