Skip to content
目录

命令系统与链式 API

1. 命令系统的目标

Tiptap 对 ProseMirror command 做了三层统一:

  • editor.commands.xxx():直接执行。
  • editor.chain().xxx().yyy().run():批量串联、一次 dispatch。
  • editor.can().xxx():可执行性预检查,不改状态。

核心实现:packages/core/src/CommandManager.ts

2. commands:单命令执行

CommandManager.commands 做的事:

  1. 拿到当前 tr 与 command props。
  2. 调用 raw command,获取回调结果。
  3. 若未设置 preventDispatch 且非 customState,则 view.dispatch(tr)

这种设计把“命令逻辑”和“何时 dispatch”解耦,支持 can/chain 复用同一套 command 定义。

3. chain:事务聚合

createChain(startTr?, shouldDispatch=true)

  • 所有 chained command 都操作同一个 tr
  • 每个 command 返回布尔值,存入 callbacks。
  • run() 时统一 dispatch,并返回 every(callback === true)

好处:

  • 避免多次 dispatch 带来的性能与中间态复杂度。
  • 保持链式语义清晰(focus -> toggle -> scrollIntoView)。

4. can:无副作用探测

createCan() 的关键是把 dispatch 置为 undefined,并复用 command 执行路径。
这让 can() 不是简单“静态判断”,而是“以当前状态模拟执行并看结果”。

5. createChainableState:让状态和事务保持同步视图

位置:packages/core/src/helpers/createChainableState.ts

该函数返回一个“可链式状态对象”:

  • selection/doc/storedMarks 来自 transaction 的 getter。
  • 每次取 tr 都刷新这些 getter 读值。

意义:

  • 在一条 chain 内,多命令之间读取的 state 是“随着 tr 演进的最新值”。
  • 避免命令误用旧 state 导致行为偏差。

6. preventDispatchpreventUpdate

常见元数据开关:

  • preventDispatch:命令层阻止当前 tr 被自动 dispatch(常用于协同 undo/redo 包装)。
  • preventUpdate:事务已 dispatch,但抑制 update 事件(减少不必要 UI 响应)。

答题建议:强调这是“事务传播层”和“UI 事件层”的分离控制。

7. 与输入规则/粘贴规则的联动

Issue: #5046

背景:insertContent/insertContentAt 原本与输入规则/粘贴规则联动不足。
改进后支持可选触发规则,适合“流式逐字输入 markdown”场景。

这说明命令系统不是封闭层,而是和规则系统协同演进。

MIT License.