尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

LogicFlow DynamicGroup 插件 cascadeDeleteChildren 配置:删除分组时级联删除子节点的设计与实现

LogicFlow DynamicGroup 插件 cascadeDeleteChildren 配置:删除分组时级联删除子节点的设计与实现 LogicFlow DynamicGroup 插件 cascadeDeleteChildren 配置删除分组时级联删除子节点的设计与实现【免费下载链接】LogicFlowA flow chart editing framework focus on business customization. 专注于业务自定义的流程图编辑框架支持实现脑图、ER图、UML、工作流等各种图编辑场景。项目地址: https://gitcode.com/GitHub_Trending/lo/LogicFlow导读DynamicGroup动态分组是 LogicFlow 生态中用于表达「容器 / 复合对象」语义的核心插件其node:delete回调长期以来的默认行为是删除分组框时级联删除children中的全部成员节点。本文基于 2026-06-26-dynamic-group-cascade-delete-children-design.md 设计文档系统讲解该行为的历史渊源、cascadeDeleteChildren插件选项的两种语义、底层删除时序与折叠态清理原理并结合源码、测试与文档站给出可复制的配置与验证方案。读完本文你将能为把分组视为「视觉容器」而非「复合对象」的业务场景配置「删组保留子节点」并理解为什么实现必须在lf.deleteNode层面而非node:delete回调里解组。背景删除分组等于删除子节点为何成了问题在 LogicFlow 的 v1.1 版本发布说明中明确记载了一条行为变更见 upgrade-to-v1-1.zh.md删除分组节点的同时会删除属于分组的子节点。DynamicGroup插件沿用了这一语义与旧版Group插件、PoolElements泳道插件保持一致。在设计文档关联的 2026-05-18-dynamic-group-fix-design.md 与 2026-06-24-dynamic-group-membership-semantics-design.md 中children集合 nodeGroupMap映射构成了分组成员关系的核心数据模型实现见 packages/extension/src/dynamic-group/index.ts。问题在于部分业务把 DynamicGroup 仅当作视觉容器。删除分组框时期望的是「框没了框里的流程节点原样留在画布上」而不是连业务节点一起删掉。在引入配置项之前这一行为没有任何开关无法 opt-out——于是有了本设计文档的决策。决策与 APIcascadeDeleteChildren插件选项决策要点设计文档给出的已确认决策如下项决策配置名cascadeDeleteChildren配置层级仅插件级pluginsOptions.dynamicGroup默认值true与现网一致升级零成本true删除 DG 时递归删除全部成员现状false仅删除 DG成员保留在画布原位置解除children/nodeGroupMap范围仅DynamicGroup插件不改 legacyGroup、PoolElements可后续对齐节点级覆盖不做版本Minor 新能力非 breaking默认行为不变关键设计取向是「默认值保持true」保证与 v1.1 以来的现网行为完全一致、升级零成本同时刻意不做节点级properties 级覆盖避免配置矩阵膨胀。文档站 dynamic-group.zh.md 的插件配置项表格也给出了醒目的默认值提示默认仍为删组即删子节点仅当显式设为false时保留子节点。使用方式const lf new LogicFlow({ container: document.querySelector(#container), plugins: [DynamicGroup], pluginsOptions: { dynamicGroup: { // 删组时保留子节点不传或传 true 时保持级联删除 cascadeDeleteChildren: false, }, }, })对应的类型声明在插件源码中同步扩展export type DynamicGroupOptions Partial{ isCollapsed: boolean /** 为 true 时禁止手动将边连到/从分组节点默认 false */ disallowEdgeConnectToGroup: boolean /** 删除分组时是否级联删除成员默认 true */ cascadeDeleteChildren: boolean /** 拖拽节点进入分组时的感应外框样式 */ sensorOutline: SensorOutlineOptions }类型定义位于 packages/extension/src/dynamic-group/index.ts。两种语义的行为定义cascadeDeleteChildren: true默认—— 递归级联删除与插件既有removeNodeFromGroup逻辑一致删除被删 DG 的每个childId对每个childIdnodeGroupMap.delete(childId)→lf.deleteNode(childId)。若成员本身为 DGnode:delete再次触发形成递归级联嵌套分组被整体连根删除。其后逻辑不变若被删节点是某组的子成员从父组removeChild并清理 map。对应实现见 packages/extension/src/dynamic-group/index.tsremoveNodeFromGroup ({ data: node, model }: CallbackArgsnode:delete) { if (model.isGroup node.children) { const groupModel model as DynamicGroupNodeModel if (this.cascadeDeleteChildren) { forEach(Array.from(groupModel.children), (childId) { this.nodeGroupMap.delete(childId) this.lf.deleteNode(childId) }) } else { if (groupModel.children.size 0) { this.releaseGroupMembers(groupModel) } } } const groupId this.nodeGroupMap.get(node.id) if (groupId) { const group this.lf.getNodeModelById(groupId) group (group as DynamicGroupNodeModel).removeChild(node.id) this.nodeGroupMap.delete(node.id) } }cascadeDeleteChildren: false—— 仅解组、保留子节点在删除 DG之前对其直接成员执行解组不调用lf.deleteNode遍历Array.from(groupModel.children)先拷贝再迭代避免在 mutate 过程中删除集合元素。对每个childIdgroup.removeChild(childId)nodeGroupMap.delete(childId)。子节点坐标不变与其相连的边保留。若 DG 处于折叠态被隐藏的直接成员恢复visible true并清理该 DG 注册的折叠虚拟边及collapsedEdgeState等临时状态避免删组后残留「僵尸」虚拟边或错误隐藏真实边。嵌套 DG父组false时子 DG 保留且仍拥有自己的children不会 flatten 整棵子树。核心方法是新增的releaseGroupMembers见 packages/extension/src/dynamic-group/index.tsreleaseGroupMembers (groupModel: DynamicGroupNodeModel) { if (groupModel.isCollapsed) { // 复用展开路径恢复真实边与成员可见性避免删虚拟边时误删真实边 groupModel.toggleCollapse(false) } forEach(Array.from(groupModel.children), (childId) { this.detachNodeFromGroup(groupModel.id, childId) }) }其中detachNodeFromGroup完成removeChildnodeGroupMap.delete 关闭可添加态detachNodeFromGroup (groupId: string, nodeId: string) { const group this.lf.getNodeModelById(groupId) as DynamicGroupNodeModel if (!group) return group.removeChild(nodeId) this.nodeGroupMap.delete(nodeId) group.setAllowAppendChild(false) }与 #2194 场景的关系「先removeChild再删分组、子节点应可正常选中」属于 map 一致性修复与cascadeDeleteChildren选项正交。cascadeDeleteChildren: false的解组路径复用与detachNodeFromGroup一致的 map /children维护并覆盖折叠态可见性。这一点由测试 D6 专门回归见下文。实现要点为什么要在lf.deleteNode层拦截设计文档明确了主改动文件为 packages/extension/src/dynamic-group/index.ts。两个关键实现决策值得深入1. 折叠态清理先展开再解组releaseGroupMembers在分组处于折叠态时先调用groupModel.toggleCollapse(false)复用现有展开路径恢复真实边与成员可见性。设计文档明确警告不要在注销映射前用deleteEdgeById删除虚拟边否则会经onEdgeDelete误删真实边。这一警告的根源在插件的边删除处理onEdgeDelete维护了「虚拟边 ↔ 真实边」的双向索引collapsedVirtualEdges与collapsedRealEdgeToGroup见 index.ts删除虚拟边时会连带删除其映射的真实边见 index.ts。如果解组前直接删虚拟边真实边也会被误删——所以必须先toggleCollapse(false)让虚拟边被正规清理、真实边恢复可见再执行解组。2. 删除时序graphModel.deleteNode先删边、再发事件核心graphModel.deleteNode的实现见 packages/core/src/model/GraphModel.ts验证了设计文档的时序论断action deleteNode(nodeId: string) { const nodeModel this.nodesMap[nodeId].model const nodeData nodeModel.getData() this.deleteEdgeBySource(nodeId) // 先删以该节点为端点的边含折叠虚拟边 this.deleteEdgeByTarget(nodeId) this.nodes.splice(this.nodesMap[nodeId].index, 1) this.eventCenter.emit(EventType.NODE_DELETE, { // 后 emit node:delete data: nodeData, model: nodeModel, }) }也就是说node:delete事件触发时以分组为端点的边包括折叠虚拟边已经被删掉了。若在removeNodeFromGroup即node:delete回调里才做解组折叠虚拟边早已被删onEdgeDelete会连带把真实边删掉子节点虽然保留但边丢了。因此实现采用包装lf.deleteNode的方式在插件init()中保存原始方法当cascadeDeleteChildren false且待删节点是分组时先调用releaseGroupMembers再委托原始deleteNodedestroy()时还原见 index.ts 与 index.tsthis.originDeleteNode lf.deleteNode.bind(lf) lf.deleteNode (nodeId: string): boolean { const nodeModel lf.getNodeModelById(nodeId) if (!this.cascadeDeleteChildren nodeModel?.isGroup) { const groupModel nodeModel as DynamicGroupNodeModel if (groupModel.children.size 0) { this.releaseGroupMembers(groupModel) } } return this.originDeleteNode!(nodeId) }非目标不修改 packages/extension/src/materials/grouplegacyGroup插件。不在本期修改PoolElements.removeNodeFromGroup文档注明后续可对齐。测试验证delete-behavior.test.ts 全场景覆盖设计文档规划的单测落到了 packages/extension/test/dynamic-group/delete-behavior.test.ts六条设计用例D1–D6全部实现另附一条「调用次数」断言D7ID场景断言要点测试证据D1默认未传 option删含子节点的 DG子节点从graphModel移除delete-behavior.test.ts#L97-L105D2cascadeDeleteChildren: false删 DGDG 消失子节点仍在getGroupByNodeId(childId)为undefineddelete-behavior.test.ts#L107-L116D3D2 子节点有对外边边仍存在且visible truedelete-behavior.test.ts#L118-L127D4嵌套 DG父false子 DG 保留且仍含其 childrendelete-behavior.test.ts#L129-L147D5折叠 DG false成员可见无残留虚拟边真实边状态正确delete-behavior.test.ts#L149-L166D6先removeChild再删空 DG与 #2194 一致选中子节点无报错回归delete-behavior.test.ts#L168-L186D7cascadeDeleteChildren: false删 DGreleaseGroupMembers恰好被调用 1 次防止包装层与事件回调双重解组delete-behavior.test.ts#L188-L198D5 是折叠态清理逻辑的完整验证先toggleCollapse(true)隐藏成员并生成 1 条虚拟边删组后断言成员visible恢复true、虚拟边归零、外部真实边e_outer_inner仍存在且可见。测试夹具定义在 packages/extension/test/dynamic-group/fixtures.ts其中createDynamicGroupLF通过pluginsOptions.dynamicGroup注入选项graphWithSingleExternalEdge构造「外节点 → 组内单节点」的最小场景。文档与发布变更的落地方式文档站已随实现更新pluginsOptions.dynamicGroup的配置项表格已加入cascadeDeleteChildren行见 dynamic-group.zh.md并附醒目提示关于cascadeDeleteChildren默认值默认为true与 v1.1 以来行为一致——删除分组会同时删除组内节点。若业务将分组视为视觉容器而非复合对象可显式设为false以保留子节点。同时给出了完整可复制的配置示例dynamic-group.zh.mdconst lf new LogicFlow({ container: document.querySelector(#container), plugins: [DynamicGroup], pluginsOptions: { dynamicGroup: { cascadeDeleteChildren: false, }, }, })CHANGELOG已随 2.3.0 发布packages/extension/CHANGELOG.md 在 2.3.0 版本记录feat(dynamic-group): 新增插件选项cascadeDeleteChildren默认true与历史一致。设为false时删除分组仅解除成员关系子节点保留在画布。验证与运行设计文档给出的验证命令可在仓库根目录执行pnpm test -- --testPathPatterndynamic-group cd packages/extension pnpm run dev cd examples/dynamic-group-regression pnpm dev第一条运行 DynamicGroup 相关全部单测含delete-behavior.test.ts第二条启动扩展包的本地开发构建第三条启动 examples/dynamic-group-regression 回归示例可手动验证删组行为设计文档注明「删组保留子节点」操作按钮为可选若单测覆盖充分可不加。总结cascadeDeleteChildren是 DynamicGroup 插件在「复合对象」与「视觉容器」两种业务语义之间提供的一个开关默认true保持 v1.1 以来的级联删除行为显式设false则仅删除分组框、成员保留原位置并解除归属。其实现的关键不在于removeNodeFromGroup里的分支判断而在于利用包装lf.deleteNode抢在graphModel.deleteNode删除端点边含折叠虚拟边之前完成解组从而避免虚拟边经onEdgeDelete连带误删真实边。这一「默认零成本升级 显式 opt-out 先展开后解组」的组合设计值得在阅读 index.ts 与 delete-behavior.test.ts 时细细品味。【免费下载链接】LogicFlowA flow chart editing framework focus on business customization. 专注于业务自定义的流程图编辑框架支持实现脑图、ER图、UML、工作流等各种图编辑场景。项目地址: https://gitcode.com/GitHub_Trending/lo/LogicFlow创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表