LogicFlow 实例注册 API 全解析:register 与 batchRegister 实现自定义节点与边
【免费下载链接】LogicFlowA flow chart editing framework focus on business customization. 专注于业务自定义的流程图编辑框架,支持实现脑图、ER图、UML、工作流等各种图编辑场景。项目地址: https://gitcode.com/GitHub_Trending/lo/LogicFlow
本文以 LogicFlow 官方 API 文档《注册》为骨架,深入讲解 LogicFlow 实例方法register与batchRegister的完整用法:从签名、参数类型、核心示例,到二者内部实现原理(viewMap / modelMap 注册表、observer包装、内置元素默认注册)逐一拆解。读完本文,你将掌握在 LogicFlow 中注册自定义节点/边的两种方式,并能结合源码理解注册失败时的报错链路,从容应对"找不到 XX 对应的节点"这类常见问题。
概述:注册机制在 LogicFlow 中的位置
LogicFlow 是一个专注于业务自定义的流程图编辑框架(见 README.md),支持脑图、ER 图、UML、工作流等多种图编辑场景。它的扩展能力建立在"注册(Register)"机制之上:任何自定义节点、自定义边,都必须先通过注册告诉实例"这个 type 长什么样(view)"以及"这个 type 有哪些数据行为(model)",之后才能在图数据中被引用、渲染和交互。
本页 API 文档位于 register.zh.md,隶属于"LogicFlow 实例"分组(order: 2),是官方 API 文档中关于实例级注册方法的唯一入口。它覆盖两个核心方法:
| 方法 | 作用 | 签名 |
|---|---|---|
register | 注册单个自定义节点或边 | register(config: RegisterConfig): void |
batchRegister | 批量注册多个自定义节点或边 | batchRegister(configList: RegisterConfig[]): void |
插件(Extension)的全局注册不在实例方法范畴内,而是通过 LogicFlow.use 完成,本文不展开。
register:注册单个自定义节点或边
register用于向当前 LogicFlow 实例注册一个自定义节点或边,是使用频率最高的扩展入口。
签名与参数
register(config: RegisterConfig): void参数类型RegisterConfig的完整定义,见类型文档 MainTypes.zh.md。它包含以下属性:
| 属性名 | 类型 | 描述 |
|---|---|---|
type | string | 指定要注册的图元素类型,必填。它是后续addNode、addEdge、render时引用该元素的唯一标识。 |
view | ComponentType<any> & { isObserved?: boolean } | 与图元素关联的视图组件(React 组件)。可包含可选布尔值isObserved,指示该组件是否已被观察(mobx 响应式)。 |
model | GraphElementCtor | 定义图元素的模型构造函数,必填。应为BaseNodeModelCtor(节点模型)或BaseEdgeModelCtor(边模型),见 LogicFlow.tsx。 |
isObserverView | boolean (可选) | 指示视图是否为观察者视图。设为true表示视图会响应模型变化(默认行为);设为false可跳过observer包装。 |
官方示例:自定义矩形节点
文档给出的标准示例,是继承内置RectNode/RectNodeModel实现一个圆角矩形节点:
import { RectNode, RectNodeModel } from '@logicflow/core'; class CustomRectNode extends RectNode {} class CustomRectModel extends RectNodeModel { setAttributes() { this.width = 200; this.height = 80; this.radius = 50; } } lf.register({ type: 'custom-rect', view: CustomRectNode, model: CustomRectModel, });拆解这段代码:
- view:
CustomRectNode继承自RectNode,不重写任何渲染逻辑,直接复用内置矩形的 SVG 渲染。 - model:
CustomRectModel继承自RectNodeModel,在setAttributes()生命周期钩子中重定义尺寸与圆角(宽 200、高 80、圆角半径 50)。setAttributes在模型初始化时被调用,是自定义节点最常见的覆写入口。 - type:
'custom-rect'是自定义的标识,之后通过lf.addNode({ type: 'custom-rect', x: 100, y: 100 })即可实例化该节点。
注册边的方式完全一致,只需将view/model换成边对应的基类(如PolylineEdge/PolylineEdgeModel),并把type设为边类型。
官方示例:批量注册多个元素
当需要一次性注册多个自定义元素时,使用batchRegister:
lf.batchRegister([ { type: 'user', view: UserNode, model: UserModel, }, { type: 'user1', view: UserNode1, model: UserModel1, }, ]);它接受RegisterConfig[]数组,内部逐项执行与register相同的注册逻辑,适用于"一次引入、注册一整套业务元素"的场景。
源码解读:register 到底做了什么
只看用法难免知其然不知其所以然。下面结合 packages/core/src/LogicFlow.tsx 的实现,说明注册的内部链路。
注册的两种重载方式
register在源码中有两个重载(LogicFlow.tsx):
register(element: RegisterConfig): void register( type: string, fn: RegisterElementFunc, isObserverView?: boolean, ): void- 方式一(推荐):传入
RegisterConfig对象,即文档示例的写法。 - 方式二:传入
type与一个RegisterElementFunc函数。源码注释明确标注该方式"不推荐,极个别在自定义的时候需要用到 lf 的情况下可以用这种方式",因为大多数场景可以直接在 view 中通过this.props获取graphModel,或在 model 中通过this.graphModel获取方法(LogicFlow.tsx)。
方式二的函数签名来自类型文档中的RegisterElementFunc与RegisterParam(见 MainTypes.zh.md):
export type RegisterElementFunc = (params: RegisterParam) => RegisterElement export type RegisterParam = { h: typeof h; // hyperscript 函数,用于创建虚拟 DOM [key: string]: unknown; // 其它由框架注入的基类(RectNode、RectNodeModel 等)与用户自定义属性 }执行方式二时,源码会构造一个registerParam对象,把内置的BaseNode、BaseEdgeModel、RectNode、RectNodeModel、PolylineEdge、BezierEdgeModel、h以及当前type全部注入(LogicFlow.tsx),随后从函数返回值中解构出view与model完成注册。
registerElement:注册的核心实现
无论哪种方式,最终都会收敛到registerElement(LogicFlow.tsx):
private registerElement(config: RegisterConfig) { let ViewComp = config.view if (config.isObserverView !== false && !ViewComp.isObserved) { ViewComp.isObserved = true ViewComp = observer(ViewComp) } this.setView(config.type, ViewComp) this.graphModel.setModel(config.type, config.model) }关键点:
- observer 包装:只要
isObserverView不为false且视图尚未被包装(isObserved为假),就会用 mobx 的observer()把视图组件包一层,使其响应模型变化。这就是为什么文档中view类型上带有isObserved?: boolean标记。 - 视图注册表 viewMap:
setView把type → ViewComp存入this.viewMap(Map),供渲染层按类型查找视图。 - 模型注册表 modelMap:
this.graphModel.setModel(type, config.model)把type → ModelClass存入GraphModel的modelMap(见 GraphModel.ts),供数据层按类型实例化模型。
内置元素的默认注册
实际上,实例初始化时就已经通过batchRegister注册了一批内置元素。defaultRegister中定义并注册了 11 个默认类型(LogicFlow.tsx):
- 节点:
rect、circle、polygon、text、ellipse、diamond、html - 边:
line、polyline、bezier
private defaultRegister() { const defaultElements: RegisterConfig[] = [ { type: 'rect', view: _View.RectNode, model: _Model.RectNodeModel }, { type: 'circle', view: _View.CircleNode, model: _Model.CircleNodeModel }, // ... polyline / bezier 等 ] this.batchRegister(defaultElements) }这解释了为什么直接使用type: 'rect'无需任何注册——它早已随实例初始化注册完毕。同时这也是batchRegister的第一个真实使用者,可见"批量注册"本就是框架内部的常规操作。
注册与消费:一次完整的闭环
注册不是终点,注册表最终服务于数据渲染。在 GraphModel.ts 中,getModel(type)负责从modelMap按类型取出模型构造函数:
getModel(type: string) { return this.modelMap.get(type) }渲染数据转换为模型时,会先查注册表,查不到即抛出错误。例如节点转换(GraphModel.ts):
const Model = this.getModel(node.type) as BaseNodeModelCtor if (!Model) { throw new Error( `找不到${node.type}对应的节点,请确认是否已注册此类型节点。`, ) }边转换同理(GraphModel.ts):
const Model = this.getModel(type) as BaseEdgeModelCtor if (!Model) { throw new Error(`找不到${type}对应的边。`) }这两处正是新手最常遇到报错的根源:图数据中出现了未注册的 type。排查方法很直接——检查register/batchRegister是否覆盖了数据中的所有type。
由此可以得到一个清晰的注册消费闭环:
lf.register({ type, view, model }) │ ▼ viewMap(type → 视图组件) ──► 渲染阶段:getView(type) 渲染 modelMap(type → 模型类) ──► 数据阶段:getModel(type) 实例化模型 │ type 未注册则抛出 "找不到 XX 对应的节点/边"实践建议与注意事项
结合文档与源码,总结以下实战要点:
- type 全局唯一:
type既是注册表键,也是图数据中的引用标识。重复注册同名 type 会覆盖之前的注册,跨实例注册互不影响(注册表挂在具体实例的 viewMap / modelMap 上)。 - 优先对象式注册:
register(config)的写法清晰直观,是推荐用法;函数式重载仅在确需访问lf场景才使用(源码注释明确标注"不推荐")。 - 默认 isObserverView 为 true:若自定义视图内部自行处理了响应式(例如使用外部状态),可通过
isObserverView: false跳过 observer 包装以省去无谓渲染开销。 - 依赖内置基类:自定义节点/边应继承
@logicflow/core导出的基类(RectNode、PolylineEdge、对应 Model 等),而不是从零实现,这样能复用渲染、选中、连线等成熟能力。 - 批处理用 batchRegister:元素较多时用
batchRegister一次注册,语义更清晰;框架自身的内置注册也是这么做的。 - 排查"找不到"报错:遇到
找不到${type}对应的节点/边,优先核对:该 type 是否已注册?注册的 type 字符串是否与图数据中的 type 完全一致(注意大小写与空格)?
关联文档索引
- 本文依据的 API 文档:register.zh.md
- 参数类型定义:MainTypes.zh.md(含
RegisterConfig、RegisterElementFunc、RegisterParam、BaseNodeModelCtor、BaseEdgeModelCtor) - 核心实现:LogicFlow.tsx(
register/registerElement/batchRegister/defaultRegister)、GraphModel.ts(getModel/setModel) - 插件注册方式:use.zh.md
- 更多实战注册示例,可参考教程目录中的扩展类文档(如 group.zh.md、dynamic-group.zh.md)以及 examples/feature-examples/src/components/nodes 下的自定义节点示例源码。
【免费下载链接】LogicFlowA flow chart editing framework focus on business customization. 专注于业务自定义的流程图编辑框架,支持实现脑图、ER图、UML、工作流等各种图编辑场景。项目地址: https://gitcode.com/GitHub_Trending/lo/LogicFlow
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考