import{ax as i,z as a,A as n,b5 as l}from"./chunks/framework.DRScawWW.js";const g=JSON.parse('{"title":"editorService方法","description":"","frontmatter":{},"headers":[],"relativePath":"api/editor/editorServiceMethods.md","filePath":"api/editor/editorServiceMethods.md"}'),t={name:"api/editor/editorServiceMethods.md"};function e(h,s,p,k,d,r){return n(),a("div",null,[...s[0]||(s[0]=[l(`
下列 DSL 操作方法(add、remove、update 等)的 options / data 参数,以及 codeBlockService / dataSourceService 的 options,在 doNotPushHistory 之外还可传入:
{string} historyDescription:入栈时附带的人类可读描述,用于历史面板展示;不影响 undo/redo 行为,缺省时面板会自动生成描述{HistoryOpSource} historySource:操作途径,用于历史面板展示与埋点;不影响 undo/redo 行为,缺省时面板视为「未知」编辑器内置交互(画布、树面板、配置面板、右键菜单、快捷键等)会自动传入对应的 historySource; 业务侧程序化调用时建议显式传入(如 api),便于历史面板区分来源。
每条历史记录入栈时都会自动生成一个唯一标识 uuid(见 StepValue),可用于精确引用 / 定位某一条历史记录(如埋点、回滚、跨端同步等)。
DSL 操作方法(add / remove / update 等)默认返回操作结果(节点 / 节点集合 / void),不会返回 uuid。若需要同时拿到原操作结果与本次写入历史记录的 uuid,可改用对应的 *AndGetHistoryId 方法:它们与原方法行为完全一致,返回值类型为 DslOpWithHistoryIdsResult<T>(result 为原方法返回值,historyIds 为本次写入的 uuid 列表)。当本次操作未写入历史(doNotPushHistory: true、无实际变更或提前返回)时 historyIds 为 [];单次操作通常返回含一个 uuid 的数组。
| 原方法 | 取 uuid 的方法 | 返回值 |
|---|---|---|
| add | addAndGetHistoryId | Promise<DslOpWithHistoryIdsResult<MNode | MNode[]>> |
| remove | removeAndGetHistoryId | Promise<DslOpWithHistoryIdsResult<void>> |
| update | updateAndGetHistoryId | Promise<DslOpWithHistoryIdsResult<MNode | MNode[]>> |
| moveLayer | moveLayerAndGetHistoryId | Promise<DslOpWithHistoryIdsResult<void>> |
| moveToContainer | moveToContainerAndGetHistoryId | Promise<DslOpWithHistoryIdsResult<MNode | MNode[]>> |
| dragTo | dragToAndGetHistoryId | Promise<DslOpWithHistoryIdsResult<void>> |
dataSourceService / codeBlockService 也提供了同名约定的 *AndGetHistoryId 方法,返回值约定相同(result + historyIds)。
拿到 uuid 后,可在需要时按 uuid「回滚」对应的历史记录(类 git revert 语义,详见历史记录面板)。相比按 index 回滚,uuid 不会随栈内步骤增删而变化,更适合业务侧持有引用后再回滚:
/**
* 历史记录写入相关的通用配置(codeBlock / dataSource / editor 共用)
* - doNotPushHistory: 操作完成后是否不要将本次操作压入历史栈(撤销/重做记录),默认 false
* - historyDescription: 入栈时附带的人类可读描述,用于历史面板展示;不影响 undo/redo 行为,缺省时面板会自动生成描述
* - historySource: 操作途径,取值见 {@link HistoryOpSource}(画布 / 树面板 / 组件面板 / 配置面板 / 源码编辑器 / 右键菜单 / 工具栏 / 快捷键 / 回滚 / 接口 等),用于历史面板展示与埋点;不影响 undo/redo 行为
*/
export interface HistoryOpOptions {
doNotPushHistory?: boolean;
historyDescription?: string;
historySource?: HistoryOpSource;
}/**
* DSL 修改类操作的通用配置
* - doNotSelect: 操作后是否不要自动触发选中(不调用 this.select / this.multiSelect / stage.select / stage.multiSelect)
* - doNotSwitchPage: 操作若会引发当前页面切换(如新增 / 删除 / 跨页移动),是否跳过这次切换
*/
export interface DslOpOptions extends HistoryOpOptions {
doNotSelect?: boolean;
doNotSwitchPage?: boolean;
}/** *AndGetHistoryId 系列方法返回值:原操作结果 + 本次写入历史记录的 uuid 列表(未入栈时为 \`[]\`)。 */
export type DslOpWithHistoryIdsResult<T> = {
result: T;
historyIds: string[];
};/**
* 历史记录的「操作途径」——标记本次变更由哪条交互入口触发,仅用于历史面板展示 / 业务埋点,
* 不影响 undo/redo 行为。缺省(未传)时 UI 视为「未知」。
*
* - \`stage\`:画布(拖拽 / 缩放 / 排序等舞台直接操作)
* - \`tree\`:树形面板(图层 / 数据源 / 代码块等树形结构里的拖拽 / 菜单操作)
* - \`component-panel\`:组件面板(左侧组件列表点击 / 拖拽新增组件)
* - \`props\`:配置面板表单(属性表单字段编辑)
* - \`code\`:源码编辑器(配置面板「源码」面板里直接编辑 JSON/代码后保存)
* - \`stage-contextmenu\`:画布右键菜单(舞台上节点的右键上下文菜单)
* - \`tree-contextmenu\`:树面板右键菜单(图层 / 数据源 / 代码块等树形列表上的右键上下文菜单)
* - \`toolbar\`:工具栏菜单(顶部导航工具栏按钮)
* - \`shortcut\`:键盘快捷键
* - \`rollback\`:历史回滚(历史面板里对某条历史「回滚」,反向应用为一条新记录,类 git revert)
* - \`api\`:代码 / 接口调用(程序化触发)
* - \`ai\`:AI 生成 / 智能助手触发的变更
* - \`unknown\`:未知来源
*
* 通过 \`(string & {})\` 允许业务侧扩展自定义途径字符串,同时保留内置值的自动补全。
*/
export type HistoryOpSource =
| 'initial'
| 'stage'
| 'tree'
| 'component-panel'
| 'props'
| 'code'
| 'root-code'
| 'stage-contextmenu'
| 'tree-contextmenu'
| 'toolbar'
| 'shortcut'
| 'rollback'
| 'api'
| 'ai'
// 同步
| 'sync'
| 'unknown'
| (string & {});参数:
{'root' | 'page' | 'parent' | 'node' | 'highlightNode' | 'nodes' | 'modifiedNodeIds' | 'pageLength' | 'pageFragmentLength' | 'stage' | 'stageLoading' | 'disabledMultiSelect' | 'alwaysMultiSelect'} name返回:
{any} value详情:
获取当前指指定name的值
'root': 当前整个配置,也就是当前编辑器的值
'page': 当前正在编辑的页面配置
'parent': 当前选中的节点的父节点
'node': 当前选中的第一个节点
'highlightNode': 当前高亮的节点
'nodes': 当前选中的所有节点
'modifiedNodeIds': 当前页面所有改动过的节点id
'pageLength': 所以页面个数
'pageFragmentLength': 页面片个数
'stage': StageCore实例
'stageLoading': 画布是否加载中
'disabledMultiSelect': 是否禁用多选
'alwaysMultiSelect': 是否始终启用多选模式(无需按住 Ctrl/Meta)
示例:
import { editorService } from "@tmagic/editor";
const node = editorService.get("node");{'root' | 'page' | 'parent' | 'node' | 'highlightNode' | 'nodes' | 'modifiedNodeIds' | 'pageLength' | 'pageFragmentLength' | 'stage' | 'stageLoading' | 'disabledMultiSelect' | 'alwaysMultiSelect'} name
{any} value
详情: 参考get方法
示例:
import { editorService } from "@tmagic/editor";
const node = editorService.get("node");
editorService.set("node", {
...node,
name: "new name",
});{number | string} id 组件id{boolean} raw 是否使用toRaw,默认为trueTIP
如果raw为false,对获取到的对象进行操作会触发vue响应式处理
返回:
EditorNodeInfo}export interface EditorNodeInfo {
node: MNode | null;
parent: MContainer | null;
page: MPage | MPageFragment | null;
path: MNode[];
}export type MNode = MComponent | MContainer | MIteratorContainer | MPage | MApp | MPageFragment;export interface MContainer extends MComponent {
/** 容器类型,默认为'container' */
type?: NodeType.CONTAINER | string;
/** 容器子元素 */
items: (MComponent | MContainer)[];
}export interface MPage extends MContainer {
/** 页面类型 */
type: NodeType.PAGE;
}export interface MPageFragment extends MContainer {
/** 页面类型 */
type: NodeType.PAGE_FRAGMENT;
}详情:
根据id获取组件、组件的父组件以及组件所属的页面节点
示例:
import { editorService } from "@tmagic/editor";
const info = editorService.getNodeInfo("text_123");
console.log(info.node);
console.log(info.parent);
console.log(info.page);参数:
{number | string} id{boolean} raw 是否使用toRaw,默认为true返回:
MNode} 组件节点配置export type MNode = MComponent | MContainer | MIteratorContainer | MPage | MApp | MPageFragment;export interface MComponent {
/** 组件ID,默认为\${type}_\${number}}形式, 如:page_123 */
id: Id;
/** 组件类型 */
type?: string;
/** 组件显示名称 */
name?: string;
/** 组件根Dom上的class */
className?: string;
/* 关联事件集合 */
events?: EventConfig[];
/** 是否隐藏 */
visible?: boolean;
/** 显示条件中配置的数据源条件的编译结果 */
condResult?: boolean;
/** 组件根Dom的style */
style?: StyleSchema;
[NODE_CONDS_KEY]?: DisplayCond[];
[NODE_CONDS_RESULT_KEY]?: boolean;
[key: string]: any;
}export interface MContainer extends MComponent {
/** 容器类型,默认为'container' */
type?: NodeType.CONTAINER | string;
/** 容器子元素 */
items: (MComponent | MContainer)[];
}export interface MIteratorContainer extends MContainer {
type: 'iterator-container';
iteratorData: any[];
dsField: string[];
itemConfig: {
layout: string;
[NODE_CONDS_KEY]: DisplayCond[];
style: Record<string, string | number>;
};
}export interface MPage extends MContainer {
/** 页面类型 */
type: NodeType.PAGE;
}export interface MApp extends MComponent {
/** App页面类型,app作为整个结构的根节点;有且只有一个 */
type: NodeType.ROOT;
/** */
items: (MPage | MPageFragment)[];
/** 代码块 */
codeBlocks?: CodeBlockDSL;
dataSources?: DataSourceSchema[];
dataSourceDeps?: DataSourceDeps;
dataSourceCondDeps?: DataSourceDeps;
dataSourceMethodDeps?: DataSourceDeps;
}export interface MPageFragment extends MContainer {
/** 页面类型 */
type: NodeType.PAGE_FRAGMENT;
}详情:
根据id获取组件的信息
示例:
import { editorService } from "@tmagic/editor";
const node = editorService.getNodeById("text_123");
console.log(node);参数:
{number | string} id{boolean} raw 是否使用toRaw,默认为true返回:
MNode} 指点组件的父节点配置详情:
根据ID获取指点节点的父节点配置
示例:
import { editorService } from "@tmagic/editor";
const parent = editorService.getParentById("text_123");
console.log(parent);参数:
MNode} node 节点配置返回:
{boolean} true 表示该节点位于非当前页面(即选中该节点将会引起当前页面切换)详情:
判断给定节点是否位于非当前页面,通常用于配合 doNotSwitchPage 选项判断 DSL 操作是否会引起页面切换
示例:
import { editorService } from "@tmagic/editor";
const otherPageNode = editorService.getNodeById("text_456");
if (editorService.isOnDifferentPage(otherPageNode)) {
console.log("该节点在其它页面,操作会触发页面切换");
}扩展支持: 是
参数:
MNode} parentMNode} node 可选返回:
Layout>} 当前布局模式/** 容器布局 */
export enum Layout {
FLEX = 'flex',
FIXED = 'fixed',
RELATIVE = 'relative',
ABSOLUTE = 'absolute',
}详情:
只有容器拥有布局,目前支持的布局有流式布局(relative),绝对定位布局(absolute),固定定位布局(fixed)
TIP
固定定位布局需要从当前选中节点判断,固需要传递可选参数 node
其他布局则是从父组件(容器)来判断
示例:
import { editorService } from "@tmagic/editor";
const parent = editorService.getParentById("text_123");
editorService.getLayout(parent).then((layout) => {
console.log(parent);
});扩展支持: 是
参数:
MNode} config 需要选中的节点或节点ID返回:
MNode>} 当前选中的节点配置详情:
选中指点节点(将指点节点设置成当前选中状态)
TIP
editorService.select只是设置了编辑器的选中状态,并没有设置画布的选中状态,所以根据实际情况可以调用stage.select来设置画布的选中态
示例:
import { editorService } from "@tmagic/editor";
editorService.select("text_123");
editorService.get("stage")?.select("text_123");参数:
返回:
{Promise<void>}详情:
选中多个节点
TIP
editorService.multiSelect只是设置了编辑器的选中状态,并没有设置画布的选中状态,所以根据实际情况可以调用stage.multiSelect来设置画布的选中态
示例:
import { editorService } from "@tmagic/editor";
editorService.multiSelect(["text_123", "button_123"]);
editorService.get("stage")?.multiSelect(["text_123", "button_123"]);返回:
MNode | null>} 选中后的节点配置详情:
选中当前节点同层级(同一父节点)的下一个节点,已经是最后一个时回到第一个
返回:
MNode>} 选中后的页面配置详情:
选中下一页,已经是最后一页时回到第一页
返回:
{void}详情:
选中根节点(root),同时清空当前选中的页面、父节点、画布及高亮节点
扩展支持: 是
参数:
MNode} config 需要高亮的节点或节点ID返回:
{Promise<void>}详情:
高亮指定节点
示例:
import { editorService } from "@tmagic/editor";
editorService.highlight("text_123");扩展支持: 是
参数:
{MNode} node 新组件节点
{MContainer} parent 指定的容器节点
返回:
MNode>} 新增的组件详情:
往指定的容器中添加组件
扩展支持: 是
参数:
{MNode | MNode[]} node 新组件节点配置或多个节点集合
{MContainer} parent 指定的容器组件节点配置,如果不设置,默认为当前选中的组件的父节点
{Object} options 可选配置
{boolean} doNotSelect 添加后是否不更新当前选中节点(默认 false,添加后会选中新增的节点){boolean} doNotSwitchPage 添加后是否不切换当前页面(默认 false;新增页面 / 跨页新增时为 true 会跳过会引发页面切换的选中操作){boolean} doNotPushHistory 是否不写入历史记录(默认 false){string} historyDescription 见历史记录相关 options{HistoryOpSource} historySource 见历史记录相关 options返回:
MNode | MNode[]>} 新增的组件或组件集合详情:
往指定的容器或当前容器中添加组件
扩展支持: 是
参数:
MNode} node 要删除的节点{Object} options 可选配置 {boolean} doNotSelect 删除后是否不更新当前选中节点(默认 false){boolean} doNotSwitchPage 删除后是否不切换当前页面(默认 false;删除页面 / 页面片段时为 true 会跳过自动切换到首个剩余页面)返回:
{Promise<void>}详情:
删除指定的组件或者页面
TIP
无论是否传入 doNotSelect / doNotSwitchPage,当被删除节点在当前选中列表中时,state 都会自动移除该节点的引用;当被删除的正好是当前页面时,state.page 也会同步清空,避免持有已删除节点
扩展支持: 是
参数:
MNode | MNode[])} node 要删除的节点或节点集合{Object} options 可选配置 {boolean} doNotSelect 删除后是否不更新当前选中节点(默认 false,删除后会选中父节点或首个页面){boolean} doNotSwitchPage 删除后是否不切换当前页面(默认 false;删除页面 / 页面片段时为 true 会跳过自动切换到首个剩余页面){boolean} doNotPushHistory 是否不写入历史记录(默认 false){string} historyDescription 见历史记录相关 options{HistoryOpSource} historySource 见历史记录相关 options返回:
{Promise<void>}详情:
删除指定的组件或者页面或组件集合
扩展支持: 是
参数:
MNode} config 新的节点{Object} data 可选配置 ChangeRecord[]} changeRecords 变更记录返回:
{Promise<{ newNode: MNode; oldNode: MNode; changeRecords?: ChangeRecord[] }>} 更新前后的节点信息export interface ChangeRecord {
propPath?: string;
value: any;
}详情:
更新节点
TIP
节点中应该要有id,不然不知道要更新哪个节点
当被更新节点正好在当前选中列表中时,state 会自动同步到新的节点引用,无需调用方处理
当被更新节点正好是当前页面时,state.page 也会同步到新的节点引用;更新非当前页面(不同 ID)时不会把编辑器切到该页
扩展支持: 是
参数:
MNode | MNode[]} config 新的节点或节点集合{Object} data 可选配置 ChangeRecord[]} changeRecords 单节点 form 端变更记录(多节点场景下被忽略,使用 changeRecordList)ChangeRecord[][]} changeRecordList 多节点 form 端变更记录列表,按 config 数组同序对应每个节点;优先级高于 changeRecords{boolean} doNotPushHistory 是否不写入历史记录(默认 false){string} historyDescription 见历史记录相关 options{HistoryOpSource} historySource 见历史记录相关 optionsexport interface ChangeRecord {
propPath?: string;
value: any;
}返回:
MNode | MNode[]>} 新的节点或节点集合详情:
更新单个或多个节点
TIP
与doUpdate的区别:
update可以支持一次更新多个组件,update是通过调用doUpdate来最终实现更新的。
编辑器内部更新组件都是调用update来实现的,update除了更新操作外,还会记录历史堆,还会更新代码块关系链。
TIP
多节点场景必须使用 changeRecordList:每个节点应保留自己独立的 records,不能把多个节点的 records 合并到同一个 changeRecords 数组里,否则 doUpdate / 依赖收集 / 历史回放都会按错误的 propPath 处理。
写入历史时,每个节点的 records 会单独保存到 updatedItems[i].changeRecords;撤销/重做时若有 records,则仅按 propPath 局部更新对应字段,避免整节点替换冲掉同节点上的其它无关变更;缺省 才退化为整节点替换(如内部 sort / moveLayer / 拖动等纯快照场景)。
扩展支持: 是
参数:
{ string | number } id1{ string | number } id2{Object} options 可选配置 {boolean} doNotSelect 排序后是否不更新当前选中节点(默认 false){boolean} doNotSwitchPage 排序后是否不切换当前页面(排序只发生在同一父节点内,方法内为空操作;保留以与其它 DSL 操作 API 一致){boolean} doNotPushHistory 是否不写入历史记录(默认 false){HistoryOpSource} historySource 见历史记录相关 options返回:
{Promise<void>}详情:
将id为id1的组件移动到id为id2的组件位置上,例如:[1,2,3,4] -> sort(1,3) -> [2,1,3,4]
用于流式布局下的组件拖动更新
扩展支持: 是
参数:
MNode | MNode[]} config 需要复制的节点或节点集合返回:
{void}详情:
复制组件节点或节点集合
通过storageService.setItem,将组件节点配置存储到localStorage中
参数:
MNode | MNode[]} config 需要复制的节点或节点集合{TargetOptions} collectorOptions 可选的依赖收集器配置返回:
{void}详情:
复制节点时会同时收集组件关联的依赖(如 dataSource、codeBlock 等),并一起存储到 localStorage 中,便于粘贴时一起带入
粘贴前置操作:返回分配了新id以及校准了坐标的配置
扩展支持: 是
参数:
PastePosition} position 粘贴的坐标export interface PastePosition {
left?: number;
top?: number;
/**
* 粘贴位置X方向偏移量
*/
offsetX?: number;
/**
* 粘贴位置Y方向偏移量
*/
offsetY?: number;
}{TargetOptions} collectorOptions 可选的依赖收集器配置{Object} options 可选配置 {boolean} doNotSelect 粘贴后是否不更新当前选中节点(默认 false){boolean} doNotSwitchPage 粘贴后是否不切换当前页面(默认 false;跨页粘贴时为 true 会跳过页面切换){boolean} doNotPushHistory 是否不写入历史记录(默认 false){string} historyDescription 见历史记录相关 options{HistoryOpSource} historySource 见历史记录相关 options返回:
MNode | MNode[]>} 添加后的组件节点配置详情:
粘贴组件节点或节点集合
通过storageService.getItem,从localStorage中获取节点,然后添加到当前容器中
扩展支持: 是
参数:
MNode | MNode[]} config 需要居中的组件或者组件集合{Object} options 可选配置 {boolean} doNotSelect 居中后是否不更新当前选中节点(默认 false){boolean} doNotSwitchPage 居中后是否不切换当前页面(居中只更新节点 style,方法内为空操作;保留以与其它 DSL 操作 API 一致){boolean} doNotPushHistory 是否不写入历史记录(默认 false){string} historyDescription 见历史记录相关 options{HistoryOpSource} historySource 见历史记录相关 options返回:
MNode | MNode[]>}详情:
水平居中组件或者组件集合,仅在流式布局下有效
TIP
与doAlignCenter的区别:
alignCenter可以支持一次水平居中多个组件,alignCenter是通过调用doAlignCenter来获取到已设置好水平居中的位置信息的节点,然后调用update更新。
扩展支持: 是
参数:
{number | 'top' | 'bottom'} offset{Object} options 可选配置 {boolean} doNotPushHistory 是否不写入历史记录(默认 false){string} historyDescription 见历史记录相关 options{HistoryOpSource} historySource 见历史记录相关 options返回:
{Promise<void>}详情:
移动当前选中节点位置
用于实现上移一层、下移一层、置顶、置底
扩展支持: 是
参数:
MNode} config 需要移动的节点{string | number} targetId 容器ID{Object} options 可选配置 {boolean} doNotSelect 移动后是否不更新当前选中节点(默认 false){boolean} doNotSwitchPage 移动后是否不切换当前页面(默认 false;目标容器位于其它页面时为 true 会跳过自动选中以避免页面切换){boolean} doNotPushHistory 是否不写入历史记录(默认 false){string} historyDescription 见历史记录相关 options{HistoryOpSource} historySource 见历史记录相关 options返回:
MNode | undefined>详情:
移动到指定容器中
参数:
MNode | MNode[]} config 需要拖拽的节点或节点集合MContainer} targetParent 目标父容器{number} targetIndex 目标位置索引{Object} options 可选配置 {boolean} doNotPushHistory 是否不写入历史记录(默认 false){string} historyDescription 见历史记录相关 options{HistoryOpSource} historySource 见历史记录相关 options返回:
{Promise<void>}详情:
将节点(支持多选)拖拽到目标容器的指定位置,会自动处理跨容器布局切换并记录历史
参数: 同 add
返回:
DslOpWithHistoryIdsResult<MNode | MNode[]>>} 详情:
与 add 行为完全一致,并在返回值中额外提供 historyIds,见历史记录 uuid 与 *AndGetHistoryId
示例:
import { editorService } from "@tmagic/editor";
const { result, historyIds } = await editorService.addAndGetHistoryId(
{ type: "text", text: "hello" },
parent,
{ historySource: "api" },
);
console.log(result); // 新增节点
console.log(historyIds); // 本次新增对应的历史记录 uuid 列表,或 []参数: 同 remove
返回:
DslOpWithHistoryIdsResult<void>>} historyIds:本次写入历史记录的 uuid 列表;未写入历史时为 []详情:
与 remove 行为完全一致,并在返回值中额外提供 historyIds
参数: 同 update
返回:
DslOpWithHistoryIdsResult<MNode | MNode[]>>} 详情:
与 update 行为完全一致,并在返回值中额外提供 historyIds
参数: 同 moveLayer
返回:
DslOpWithHistoryIdsResult<void>>} historyIds:本次写入历史记录的 uuid 列表;未写入历史时为 []详情:
与 moveLayer 行为完全一致,并在返回值中额外提供 historyIds
参数: 同 moveToContainer
返回:
DslOpWithHistoryIdsResult<MNode | MNode[]>>} result:同 moveToContainer 的返回值(移动后的节点 / 节点数组)historyIds:本次写入历史记录的 uuid 列表;未写入历史时为 []详情:
与 moveToContainer 行为完全一致,并在返回值中额外提供 historyIds
参数: 同 dragTo
返回:
DslOpWithHistoryIdsResult<void>>} historyIds:本次写入历史记录的 uuid 列表;未写入历史时为 []详情:
与 dragTo 行为完全一致,并在返回值中额外提供 historyIds
参数:
{string[]} uuids 目标历史记录的 uuid 列表(通常由 *AndGetHistoryId 方法返回的 historyIds)返回:
StepValue | null)[]>} 与入参同序的回滚结果列表,某项失败时为 null详情:
通过历史记录 uuid「回滚」当前页面的历史步骤(类 git revert 语义):不移动游标、不丢弃任何步骤,而是把目标 step 的修改反向应用为一条全新的步骤压入栈顶。按数组顺序依次回滚。
TIP
opType: 'update' 的步骤必须携带 changeRecords 才支持回滚(否则只能整节点替换,会冲掉后续无关变更);未应用(已被撤销)的步骤无法回滚。
示例:
import { editorService } from "@tmagic/editor";
// 执行操作时拿到本次历史记录 uuid
const { historyIds } = await editorService.addAndGetHistoryId({ type: "text", text: "hello" });
// 之后任意时机按 uuid 回滚(支持单个或整批 historyIds)
await editorService.revertPageStepById(historyIds);扩展支持: 是
返回:
StepValue | null>}/**
* 页面节点历史记录条目(\`diff\` 内容为 {@link MNode})。结构已与代码块 / 数据源统一收敛到
* {@link BaseStepValue}:关联 id 见 \`data.id\`,选区等上下文见 \`extra\`。
*/
export type StepValue = BaseStepValue<MNode, StepExtra>;/**
* 历史记录条目公共字段,被 {@link StepValue} / {@link CodeBlockStepValue} / {@link DataSourceStepValue} 复用。
*
* 泛型 \`T\` 为 \`diff\` 中变化内容的快照类型(页面节点 \`MNode\` / 代码块 \`CodeBlockContent\` / 数据源 \`DataSourceSchema\`)。
*/
export interface BaseStepValue<T = unknown, U extends Record<string, any> = {}> {
/**
* 历史记录唯一标识(uuid)。入栈时自动写入(若调用方未指定),
* 用于精确定位 / 引用某一条历史记录(如 revert、埋点、跨端同步等)。
* 注意与 \`data.id\`(关联的页面 / 代码块 / 数据源 id)区分。
*/
uuid: string;
/**
* 关联目标信息:\`id\` 为关联的页面 / 代码块 / 数据源等资源 id(也是历史栈的分组 key),
* \`name\` 为展示名。所有历史类型统一携带。
*/
data: { name: string; id: Id };
/** 操作类型:新增 / 删除 / 更新(三类历史记录统一携带)。 */
opType: HistoryOpType;
/**
* 本次变更的内容(统一 diff 表达),每项见 {@link StepDiffItem}。
* 页面节点(add/remove 多节点、update 多节点)会有多项,代码块 / 数据源通常只有一项。
*/
diff: StepDiffItem<T>[];
/**
* 调用方可选传入的人类可读描述(如「调整按钮颜色」),用于历史面板展示。
* 不影响 undo/redo 行为;缺省时面板会根据节点 / propPath 自动生成描述。
*/
historyDescription?: string;
/**
* 操作途径:标记本次变更由哪条交互入口触发,取值见 {@link HistoryOpSource}
* (画布 / 树面板 / 组件面板 / 配置面板 / 源码编辑器 / 右键菜单 / 工具栏 / 快捷键 / 回滚 / 接口 等)。
* 仅用于历史面板展示与业务埋点,不影响 undo/redo 行为;缺省时面板视为「未知」。
*/
source?: HistoryOpSource;
/**
* 入栈时间戳(毫秒)。入栈时自动写入(若调用方未指定),仅用于历史面板展示。
*/
timestamp?: number;
/**
* 是否为「已保存」记录:DSL 落库(如保存到后端 / 本地)时由 historyService.markSaved 标记。
* 同一栈内任意时刻最多只有一条记录为 true;从 IndexedDB 恢复时游标会被定位到最近一条已保存记录之后。
*/
saved?: boolean;
/**
* 是否为「整体设置 root」(set root)产生的记录(由 {@link Editor.pushRootDiffHistory} 写入)。
* 用于「连续 set root 合并」:当某页栈最新一条已是 root 记录时,下一条 set root 会替换它而非新增,
* 避免源码反复保存 / 外部重设 DSL 时堆积多条 root 记录。
*/
rootStep?: boolean;
/** 操作人 */
operator?: string;
/** 扩展信息 */
extra?: U;
}/**
* 历史记录的扩展上下文({@link BaseStepValue.extra})。
* 内置字段供 \`page\` 类型在撤销 / 重做时恢复选区与受影响节点;扩展类型可自由附加其它键。
*/
export interface StepExtra {
/** 操作前选中的节点 ID,用于撤销后恢复选择状态(page 类型) */
selectedBefore?: Id[];
/** 操作后选中的节点 ID,用于重做后恢复选择状态(page 类型) */
selectedAfter?: Id[];
/** 本次操作涉及的节点 id 集合(page 类型) */
modifiedNodeIds?: Map<Id, Id>;
[key: string]: any;
}/**
* 历史记录操作类型:
* - \`add\` / \`remove\` / \`update\`:普通可撤销/重做的节点变更;
* - \`initial\`:页面「未修改的初始状态」基线(设置 root 时生成),作为页面栈 index 0 的固定底线 step。
* 该 step 不可被撤销/回滚(cursor 不会低于它),仅用于历史面板底部的初始行展示。
*/
export type HistoryOpType = 'add' | 'remove' | 'update' | 'initial';/**
* 历史记录的「操作途径」——标记本次变更由哪条交互入口触发,仅用于历史面板展示 / 业务埋点,
* 不影响 undo/redo 行为。缺省(未传)时 UI 视为「未知」。
*
* - \`stage\`:画布(拖拽 / 缩放 / 排序等舞台直接操作)
* - \`tree\`:树形面板(图层 / 数据源 / 代码块等树形结构里的拖拽 / 菜单操作)
* - \`component-panel\`:组件面板(左侧组件列表点击 / 拖拽新增组件)
* - \`props\`:配置面板表单(属性表单字段编辑)
* - \`code\`:源码编辑器(配置面板「源码」面板里直接编辑 JSON/代码后保存)
* - \`stage-contextmenu\`:画布右键菜单(舞台上节点的右键上下文菜单)
* - \`tree-contextmenu\`:树面板右键菜单(图层 / 数据源 / 代码块等树形列表上的右键上下文菜单)
* - \`toolbar\`:工具栏菜单(顶部导航工具栏按钮)
* - \`shortcut\`:键盘快捷键
* - \`rollback\`:历史回滚(历史面板里对某条历史「回滚」,反向应用为一条新记录,类 git revert)
* - \`api\`:代码 / 接口调用(程序化触发)
* - \`ai\`:AI 生成 / 智能助手触发的变更
* - \`unknown\`:未知来源
*
* 通过 \`(string & {})\` 允许业务侧扩展自定义途径字符串,同时保留内置值的自动补全。
*/
export type HistoryOpSource =
| 'initial'
| 'stage'
| 'tree'
| 'component-panel'
| 'props'
| 'code'
| 'root-code'
| 'stage-contextmenu'
| 'tree-contextmenu'
| 'toolbar'
| 'shortcut'
| 'rollback'
| 'api'
| 'ai'
// 同步
| 'sync'
| 'unknown'
| (string & {});export type Id = string | number;详情:
撤销当前操作
扩展支持: 是
返回:
StepValue | null>}/**
* 页面节点历史记录条目(\`diff\` 内容为 {@link MNode})。结构已与代码块 / 数据源统一收敛到
* {@link BaseStepValue}:关联 id 见 \`data.id\`,选区等上下文见 \`extra\`。
*/
export type StepValue = BaseStepValue<MNode, StepExtra>;/**
* 历史记录条目公共字段,被 {@link StepValue} / {@link CodeBlockStepValue} / {@link DataSourceStepValue} 复用。
*
* 泛型 \`T\` 为 \`diff\` 中变化内容的快照类型(页面节点 \`MNode\` / 代码块 \`CodeBlockContent\` / 数据源 \`DataSourceSchema\`)。
*/
export interface BaseStepValue<T = unknown, U extends Record<string, any> = {}> {
/**
* 历史记录唯一标识(uuid)。入栈时自动写入(若调用方未指定),
* 用于精确定位 / 引用某一条历史记录(如 revert、埋点、跨端同步等)。
* 注意与 \`data.id\`(关联的页面 / 代码块 / 数据源 id)区分。
*/
uuid: string;
/**
* 关联目标信息:\`id\` 为关联的页面 / 代码块 / 数据源等资源 id(也是历史栈的分组 key),
* \`name\` 为展示名。所有历史类型统一携带。
*/
data: { name: string; id: Id };
/** 操作类型:新增 / 删除 / 更新(三类历史记录统一携带)。 */
opType: HistoryOpType;
/**
* 本次变更的内容(统一 diff 表达),每项见 {@link StepDiffItem}。
* 页面节点(add/remove 多节点、update 多节点)会有多项,代码块 / 数据源通常只有一项。
*/
diff: StepDiffItem<T>[];
/**
* 调用方可选传入的人类可读描述(如「调整按钮颜色」),用于历史面板展示。
* 不影响 undo/redo 行为;缺省时面板会根据节点 / propPath 自动生成描述。
*/
historyDescription?: string;
/**
* 操作途径:标记本次变更由哪条交互入口触发,取值见 {@link HistoryOpSource}
* (画布 / 树面板 / 组件面板 / 配置面板 / 源码编辑器 / 右键菜单 / 工具栏 / 快捷键 / 回滚 / 接口 等)。
* 仅用于历史面板展示与业务埋点,不影响 undo/redo 行为;缺省时面板视为「未知」。
*/
source?: HistoryOpSource;
/**
* 入栈时间戳(毫秒)。入栈时自动写入(若调用方未指定),仅用于历史面板展示。
*/
timestamp?: number;
/**
* 是否为「已保存」记录:DSL 落库(如保存到后端 / 本地)时由 historyService.markSaved 标记。
* 同一栈内任意时刻最多只有一条记录为 true;从 IndexedDB 恢复时游标会被定位到最近一条已保存记录之后。
*/
saved?: boolean;
/**
* 是否为「整体设置 root」(set root)产生的记录(由 {@link Editor.pushRootDiffHistory} 写入)。
* 用于「连续 set root 合并」:当某页栈最新一条已是 root 记录时,下一条 set root 会替换它而非新增,
* 避免源码反复保存 / 外部重设 DSL 时堆积多条 root 记录。
*/
rootStep?: boolean;
/** 操作人 */
operator?: string;
/** 扩展信息 */
extra?: U;
}/**
* 历史记录的扩展上下文({@link BaseStepValue.extra})。
* 内置字段供 \`page\` 类型在撤销 / 重做时恢复选区与受影响节点;扩展类型可自由附加其它键。
*/
export interface StepExtra {
/** 操作前选中的节点 ID,用于撤销后恢复选择状态(page 类型) */
selectedBefore?: Id[];
/** 操作后选中的节点 ID,用于重做后恢复选择状态(page 类型) */
selectedAfter?: Id[];
/** 本次操作涉及的节点 id 集合(page 类型) */
modifiedNodeIds?: Map<Id, Id>;
[key: string]: any;
}/**
* 历史记录操作类型:
* - \`add\` / \`remove\` / \`update\`:普通可撤销/重做的节点变更;
* - \`initial\`:页面「未修改的初始状态」基线(设置 root 时生成),作为页面栈 index 0 的固定底线 step。
* 该 step 不可被撤销/回滚(cursor 不会低于它),仅用于历史面板底部的初始行展示。
*/
export type HistoryOpType = 'add' | 'remove' | 'update' | 'initial';/**
* 历史记录的「操作途径」——标记本次变更由哪条交互入口触发,仅用于历史面板展示 / 业务埋点,
* 不影响 undo/redo 行为。缺省(未传)时 UI 视为「未知」。
*
* - \`stage\`:画布(拖拽 / 缩放 / 排序等舞台直接操作)
* - \`tree\`:树形面板(图层 / 数据源 / 代码块等树形结构里的拖拽 / 菜单操作)
* - \`component-panel\`:组件面板(左侧组件列表点击 / 拖拽新增组件)
* - \`props\`:配置面板表单(属性表单字段编辑)
* - \`code\`:源码编辑器(配置面板「源码」面板里直接编辑 JSON/代码后保存)
* - \`stage-contextmenu\`:画布右键菜单(舞台上节点的右键上下文菜单)
* - \`tree-contextmenu\`:树面板右键菜单(图层 / 数据源 / 代码块等树形列表上的右键上下文菜单)
* - \`toolbar\`:工具栏菜单(顶部导航工具栏按钮)
* - \`shortcut\`:键盘快捷键
* - \`rollback\`:历史回滚(历史面板里对某条历史「回滚」,反向应用为一条新记录,类 git revert)
* - \`api\`:代码 / 接口调用(程序化触发)
* - \`ai\`:AI 生成 / 智能助手触发的变更
* - \`unknown\`:未知来源
*
* 通过 \`(string & {})\` 允许业务侧扩展自定义途径字符串,同时保留内置值的自动补全。
*/
export type HistoryOpSource =
| 'initial'
| 'stage'
| 'tree'
| 'component-panel'
| 'props'
| 'code'
| 'root-code'
| 'stage-contextmenu'
| 'tree-contextmenu'
| 'toolbar'
| 'shortcut'
| 'rollback'
| 'api'
| 'ai'
// 同步
| 'sync'
| 'unknown'
| (string & {});export type Id = string | number;详情:
恢复到下一步
扩展支持: 是
参数:
{number} left{number} top{Object} options 可选配置 {boolean} doNotPushHistory 是否不写入历史记录(默认 false){string} historyDescription 见历史记录相关 options{HistoryOpSource} historySource 见历史记录相关 options返回:
{Promise<void>}详情:
更新当前选中组件位置,通常用于键盘上下左右快捷键操作
重置当前记录的修改过的节点id记录,通常用于保存之后
清空state
详情:
销毁editorService
移除所有事件监听,清空state,移除所有插件
详情:
usePlugin支持灵活细致的扩展, 上述方法中标记有扩展支持: 是的方法都支持使用usePlugin扩展
每个支持扩展的方法都支持定制before、after两个hook来干预原有方法的行为,before可以用于修改传入参数,after可以用于修改返回的值
import { editorService } from "@tmagic/editor";
editorService.usePlugin({
// 添加组件的时候设置一个添加时间
beforeDoAdd: (config, parent) => {
config.addTime = new Date().getTime();
return [config, parent];
},
});删掉当前设置的所有扩展
`,128)])])}const c=i(t,[["render",e]]);export{g as __pageData,c as default};