LogicFlow 文本编辑 API 详解:editText 与 updateText 的机制、用法与源码剖析
【免费下载链接】LogicFlowA flow chart editing framework focus on business customization. 专注于业务自定义的流程图编辑框架,支持实现脑图、ER图、UML、工作流等各种图编辑场景。项目地址: https://gitcode.com/GitHub_Trending/lo/LogicFlow
导读
在 LogicFlow 流程图编辑框架中,节点与连线的文本(如节点名称、连线标签)既可以由用户直接在画布上编辑,也可以通过实例方法以编程方式控制。本文基于 LogicFlow 官方 API 文档与核心源码,系统讲解文本编辑的两个核心实例方法editText与updateText:先给出可直接套用的签名、参数与示例,再深入packages/core源码剖析其状态机切换、文本提交链路与相关事件,帮助你精确控制文本编辑的进入与内容更新,规避"文本不可编辑时编辑框无法退出"等典型陷阱。
方法总览
LogicFlow 实例(LogicFlow类实例,通常命名为lf)提供两个与节点/边文本编辑直接相关的方法:
| 方法 | 签名 | 作用 |
|---|---|---|
editText | editText(id: string): void | 显示节点、连线文本编辑框,进入编辑状态 |
updateText | updateText(id: string, value: string): void | 更新节点或边的文本内容 |
两个方法均通过实例直接调用,适用于任何已渲染进画布的节点或边元素。下面逐一展开。
editText:进入文本编辑状态
签名与参数
editText(id: string): void| 名称 | 类型 | 必传 | 说明 |
|---|---|---|---|
id | string | 是 | 节点或边 ID。 |
示例
lf.editText('node_1'); lf.editText('edge_1');调用后,对应元素会显示文本编辑框并自动聚焦,光标定位到文本末尾,用户可直接输入内容。
注意事项:文本不可编辑时的状态清理
官方文档明确强调:当初始化lf实例时设置了文本不可编辑(text.editable: false或全局关闭文本编辑),LogicFlow 内部不会自动监听并取消元素编辑状态。此时需要自行监听相关事件,并通过setElementState方法手动取消文本编辑状态。
例如:
import { ElementState } from '@logicflow/core'; lf.eventCenter.on('text:update', ({ data }) => { // 自行判断是否允许编辑,不允许时强制退出编辑态 const model = lf.getNodeModelById(data.id) || lf.getEdgeModelById(data.id); model?.setElementState(ElementState.DEFAULT); });setElementState是元素 Model(BaseModel)上的公开方法,类型声明见 BaseModel.ts,其签名含义为"设置 Node | Edge 等 model 的状态",ElementState.DEFAULT表示默认显示态。关于状态枚举的详细说明见下文"源码原理剖析"。
updateText:更新文本内容
签名与参数
updateText(id: string, value: string): void| 名称 | 类型 | 必传 | 说明 |
|---|---|---|---|
id | string | 是 | 节点或边 ID。 |
value | string | 是 | 更新后的文本值。 |
示例
lf.updateText('node_1', '审批通过'); lf.updateText('edge_1', '是');与editText不同,updateText不会进入编辑状态,而是直接替换元素的文本内容并触发视图重绘,适合在代码中同步数据、回显结果等场景。
源码原理剖析
editText与updateText在实例层只是薄封装,真正的工作发生在GraphModel与元素 Model 层。理解这条调用链,有助于你预判 API 行为。
1. 实例层的薄封装
在 LogicFlow.tsx 中,两个方法直接委托给graphModel:
editText(id: string): void { this.graphModel.editText(id) } updateText(id: string, value: string) { this.graphModel.updateText(id, value) }2. editText 的状态机本质:ElementState.TEXT_EDIT
editText的核心并非"弹出一个输入框",而是将元素状态切换为ElementState.TEXT_EDIT,视图层据此渲染TextEditTool编辑框。调用链如下:
- GraphModel.ts:
@action editText(id: string) { this.setElementStateById(id, ElementState.TEXT_EDIT) }- 状态枚举定义在 constant/index.ts:
export enum ElementState { DEFAULT = 1, // 默认显示 TEXT_EDIT, // 此元素正在进行文本编辑 SHOW_MENU, // 显示菜单(废弃,请使用菜单插件) ALLOW_CONNECT, // 此元素允许作为当前边的目标节点 NOT_ALLOW_CONNECT, // 此元素不允许作为当前边的目标节点 }setElementStateById在 GraphModel.ts 中实现,其关键语义是互斥性:遍历全部节点与边,只把目标id对应的元素设置为指定状态,其余元素一律重置为ElementState.DEFAULT,从而保证整个画布同一时刻至多只有一个元素处于文本编辑状态:
@action setElementStateById(id, state, additionStateData?) { this.nodes.forEach((node) => { if (node.id === id) { node.setElementState(state, additionStateData) } else { node.setElementState(ElementState.DEFAULT) } }) this.edges.forEach((edge) => { if (edge.id === id) { edge.setElementState(state, additionStateData) } else { edge.setElementState(ElementState.DEFAULT) } }) }- 当前正在编辑的元素由
GraphModel的计算属性textEditElement暴露,见 GraphModel.ts,其实现是低频遍历节点与边,查找state === ElementState.TEXT_EDIT的元素。
3. TextEditTool:编辑框的渲染与提交链路
当存在textEditElement时,视图层渲染 TextEditTool.tsx(toolName = 'text-edit-tool')。该组件是一个contentEditable的 div(class 为lf-text-input),其行为决定了文本编辑的交互细节:
- 自动聚焦与光标定位:
componentDidUpdate中对编辑框调用focus()并placeCaretAtEnd,把光标放到文本末尾(见 TextEditTool.tsx); - 自动换行适配:
getDerivedStateFromProps根据主题(theme.nodeText/theme.edgeText)的overflowMode === 'autoWrap'与textWidth动态设置编辑框宽度、行高与内边距,实现节点/边文案的自动换行编辑(见 TextEditTool.tsx); - 提交快捷键:按下
Alt + Enter表示输入完成,调用textEditElement.setElementState(ElementState.DEFAULT)退出编辑态(见 TextEditTool.tsx); - 内容暂存与事件:
onInput时把最新文本暂存到__prevText,并会去掉文本末尾多余的换行符(value.replace(/(\r\n)+$|(\n)+$/, ''),修复 issue #488,见 TextEditTool.tsx);在组件更新(即编辑状态切换)时,若存在暂存文本,则调用graphModel.updateText(id, text)提交,并向事件中心派发EventType.TEXT_UPDATE(见 TextEditTool.tsx)。
4. updateText 的查找与写入
updateText在 GraphModel.ts 中的实现是:在nodes与edges合并列表中按id查找元素,命中后调用元素的updateText:
@action updateText(id: string, value: string) { const element = find( [...this.nodes, ...this.edges], (item) => item.id === id, ) element?.updateText(value) }元素层的updateText在节点与边上行为一致——保留原文本的位置、可编辑、可拖拽等配置,仅替换value。节点实现见 BaseNodeModel.ts,边实现见 BaseEdgeModel.ts:
@action updateText(value: string): void { this.text = { ...toJS(this.text), value, } }注意:若传入的id既不是节点也不是边,调用会被静默忽略(element为undefined),不会抛错。
5. 文本配置 TextConfig
updateText更新的是元素text字段中的value。text的完整结构为TextConfig,定义于 LogicFlow.tsx:
export type TextConfig = { value: string x: number y: number editable?: boolean draggable?: boolean }value:文本内容;x/y:文本在画布坐标系中的位置;editable:是否允许编辑(为false时即对应前文"注意"中提到的不可编辑场景);draggable:文本是否可拖拽移动。
从源码结构可以推断:由于updateText基于toJS展开后再覆写value,调用它不会破坏元素文本原有的坐标与可编辑/可拖拽属性,适合在保持布局的前提下安全更新文案。
相关事件:监听文本编辑生命周期
文本编辑过程中,LogicFlow 会通过实例的eventCenter派发事件,事件名定义在 constant/index.ts,可用lf.on('text:update', callback)监听:
| 事件 | 说明 |
|---|---|
text:update | 文本更新(用户提交编辑或调用updateText时触发,data含id、text、type) |
text:focus | 文本获得焦点 |
text:add | 新增文本 |
text:clear | 文本清空 |
示例——监听文本更新并联动业务数据:
lf.on('text:update', ({ data }) => { console.log('文本更新:', data.id, data.text); });这一事件也是前文"文本不可编辑时清理编辑状态"建议中自行监听的首选挂载点。
常见应用场景与建议
- 通过代码进入编辑态:表单校验失败、流程补全等场景需要聚焦到特定元素的文本时,可先调用
lf.editText(id),配合text:update事件完成后续业务处理; - 通过代码同步文本:加载远端数据、撤销重做、批量改名等场景直接调用
lf.updateText(id, value),无需用户介入; - 处理不可编辑元素:当全局或元素级配置了
editable: false时,若仍调用了editText,请务必按官方提示自行监听事件并调用setElementState(ElementState.DEFAULT)清理状态,避免编辑框残留; - 文本内容与位置分离:
updateText只改内容不改位置;若需要移动文本位置,请通过TextConfig中的x/y(或元素的moveText方法,见 BaseNodeModel.ts 与 BaseEdgeModel.ts)操作。
小结
editText与updateText分别对应文本编辑的"进入编辑态"与"直接更新内容"两条路径:前者以ElementState.TEXT_EDIT状态机驱动视图渲染TextEditTool,全程由用户交互完成提交;后者则通过元素 Model 的updateText原子地替换value。掌握其底层调用链(LogicFlow → GraphModel → BaseNodeModel/BaseEdgeModel)与text:update事件,即可在业务中精确、安全地控制文本编辑行为。
本文基于当前仓库源码(
packages/core)与 官方文本编辑 API 文档 编写,文中涉及的实现细节均可通过 LogicFlow.tsx、GraphModel.ts、TextEditTool.tsx 等文件进一步查阅验证。
【免费下载链接】LogicFlowA flow chart editing framework focus on business customization. 专注于业务自定义的流程图编辑框架,支持实现脑图、ER图、UML、工作流等各种图编辑场景。项目地址: https://gitcode.com/GitHub_Trending/lo/LogicFlow
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考