Skip to content

editorService方法

历史记录相关 options

下列 DSL 操作方法(addremoveupdate 等)的 options / data 参数,以及 codeBlockService / dataSourceServiceoptions,在 doNotPushHistory 之外还可传入:

  • {string} historyDescription:入栈时附带的人类可读描述,用于历史面板展示;不影响 undo/redo 行为,缺省时面板会自动生成描述
  • {HistoryOpSource} historySource:操作途径,用于历史面板展示与埋点;不影响 undo/redo 行为,缺省时面板视为「未知」

编辑器内置交互(画布、树面板、配置面板、右键菜单、快捷键等)会自动传入对应的 historySource; 业务侧程序化调用时建议显式传入(如 api),便于历史面板区分来源。

查看 HistoryOpOptions / DslOpOptions / HistoryOpSource 类型定义
ts
/**
 * 历史记录写入相关的通用配置(codeBlock / dataSource / editor 共用)
 * - doNotPushHistory: 操作完成后是否不要将本次操作压入历史栈(撤销/重做记录),默认 false
 * - historyDescription: 入栈时附带的人类可读描述,用于历史面板展示;不影响 undo/redo 行为,缺省时面板会自动生成描述
 * - historySource: 操作途径,取值见 {@link HistoryOpSource}(画布 / 树面板 / 组件面板 / 配置面板 / 源码编辑器 / 右键菜单 / 工具栏 / 快捷键 / 回滚 / 接口 等),用于历史面板展示与埋点;不影响 undo/redo 行为
 */
export interface HistoryOpOptions {
  doNotPushHistory?: boolean;
  historyDescription?: string;
  historySource?: HistoryOpSource;
}
ts
/**
 * DSL 修改类操作的通用配置
 * - doNotSelect: 操作后是否不要自动触发选中(不调用 this.select / this.multiSelect / stage.select / stage.multiSelect)
 * - doNotSwitchPage: 操作若会引发当前页面切换(如新增 / 删除 / 跨页移动),是否跳过这次切换
 */
export interface DslOpOptions extends HistoryOpOptions {
  doNotSelect?: boolean;
  doNotSwitchPage?: boolean;
}
ts
/**
 * 历史记录的「操作途径」——标记本次变更由哪条交互入口触发,仅用于历史面板展示 / 业务埋点,
 * 不影响 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 =
  | 'stage'
  | 'tree'
  | 'component-panel'
  | 'props'
  | 'code'
  | 'stage-contextmenu'
  | 'tree-contextmenu'
  | 'toolbar'
  | 'shortcut'
  | 'rollback'
  | 'api'
  | 'ai'
  | 'unknown'
  | (string & {});

get

  • 参数:

    • {'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)

  • 示例:

js
import { editorService } from "@tmagic/editor";

const node = editorService.get("node");

set

  • {'root' | 'page' | 'parent' | 'node' | 'highlightNode' | 'nodes' | 'modifiedNodeIds' | 'pageLength' | 'pageFragmentLength' | 'stage' | 'stageLoading' | 'disabledMultiSelect' | 'alwaysMultiSelect'} name

  • {any} value

  • 详情: 参考get方法

  • 示例:

js
import { editorService } from "@tmagic/editor";

const node = editorService.get("node");

editorService.set("node", {
  ...node,
  name: "new name",
});

getNodeInfo

  • 参数:
    • {number | string} id 组件id
    • {boolean} raw 是否使用toRaw,默认为true

TIP

如果raw为false,对获取到的对象进行操作会触发vue响应式处理

  • 返回:

    • {EditorNodeInfo}
    查看 EditorNodeInfo 及关联类型定义
    ts
    export interface EditorNodeInfo {
      node: MNode | null;
      parent: MContainer | null;
      page: MPage | MPageFragment | null;
    }
    ts
    export type MNode = MComponent | MContainer | MIteratorContainer | MPage | MApp | MPageFragment;
    ts
    export interface MContainer extends MComponent {
      /** 容器类型,默认为'container' */
      type?: NodeType.CONTAINER | string;
      /** 容器子元素 */
      items: (MComponent | MContainer)[];
    }
    ts
    export interface MPage extends MContainer {
      /** 页面类型 */
      type: NodeType.PAGE;
    }
    ts
    export interface MPageFragment extends MContainer {
      /** 页面类型 */
      type: NodeType.PAGE_FRAGMENT;
    }
  • 详情:

    根据id获取组件、组件的父组件以及组件所属的页面节点

  • 示例:

js
import { editorService } from "@tmagic/editor";

const info = editorService.getNodeInfo("text_123");

console.log(info.node);
console.log(info.parent);
console.log(info.page);

getNodeById

  • 参数:

    • {number | string} id
    • {boolean} raw 是否使用toRaw,默认为true
  • 返回:

    • {MNode} 组件节点配置
    查看 MNode 及关联类型定义
    ts
    export type MNode = MComponent | MContainer | MIteratorContainer | MPage | MApp | MPageFragment;
    ts
    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;
    }
    ts
    export interface MContainer extends MComponent {
      /** 容器类型,默认为'container' */
      type?: NodeType.CONTAINER | string;
      /** 容器子元素 */
      items: (MComponent | MContainer)[];
    }
    ts
    export interface MIteratorContainer extends MContainer {
      type: 'iterator-container';
      iteratorData: any[];
      dsField: string[];
      itemConfig: {
        layout: string;
        [NODE_CONDS_KEY]: DisplayCond[];
        style: Record<string, string | number>;
      };
    }
    ts
    export interface MPage extends MContainer {
      /** 页面类型 */
      type: NodeType.PAGE;
    }
    ts
    export interface MApp extends MComponent {
      /** App页面类型,app作为整个结构的根节点;有且只有一个 */
      type: NodeType.ROOT;
      /** */
      items: (MPage | MPageFragment)[];
      /** 代码块 */
      codeBlocks?: CodeBlockDSL;
    
      dataSources?: DataSourceSchema[];
    
      dataSourceDeps?: DataSourceDeps;
      dataSourceCondDeps?: DataSourceDeps;
      dataSourceMethodDeps?: DataSourceDeps;
    }
    ts
    export interface MPageFragment extends MContainer {
      /** 页面类型 */
      type: NodeType.PAGE_FRAGMENT;
    }
  • 详情:

    根据id获取组件的信息

  • 示例:

js
import { editorService } from "@tmagic/editor";

const node = editorService.getNodeById("text_123");

console.log(node);

getParentById

  • 参数:

    • {number | string} id
    • {boolean} raw 是否使用toRaw,默认为true
  • 返回:

    • {MNode} 指点组件的父节点配置
  • 详情:

    根据ID获取指点节点的父节点配置

  • 示例:

js
import { editorService } from "@tmagic/editor";

const parent = editorService.getParentById("text_123");

console.log(parent);

isOnDifferentPage

  • 参数:

    • {MNode} node 节点配置
  • 返回:

    • {boolean} true 表示该节点位于非当前页面(即选中该节点将会引起当前页面切换)
  • 详情:

    判断给定节点是否位于非当前页面,通常用于配合 doNotSwitchPage 选项判断 DSL 操作是否会引起页面切换

  • 示例:

js
import { editorService } from "@tmagic/editor";

const otherPageNode = editorService.getNodeById("text_456");
if (editorService.isOnDifferentPage(otherPageNode)) {
  console.log("该节点在其它页面,操作会触发页面切换");
}

getLayout

  • 扩展支持

  • 参数:

    • {MNode} parent
    • {MNode} node 可选
  • 返回:

    • {Promise<Layout>} 当前布局模式
    查看 Layout 类型定义
    ts
    /** 容器布局 */
    export enum Layout {
      FLEX = 'flex',
      FIXED = 'fixed',
      RELATIVE = 'relative',
      ABSOLUTE = 'absolute',
    }
  • 详情:

    只有容器拥有布局,目前支持的布局有流式布局(relative),绝对定位布局(absolute),固定定位布局(fixed)

    TIP

    固定定位布局需要从当前选中节点判断,固需要传递可选参数 node

    其他布局则是从父组件(容器)来判断

  • 示例:

js
import { editorService } from "@tmagic/editor";

const parent = editorService.getParentById("text_123");
editorService.getLayout(parent).then((layout) => {
  console.log(parent);
});

select

  • 扩展支持

  • 参数:

    • {number | string | MNode} config 需要选中的节点或节点ID
  • 返回:

    • {Promise<MNode>} 当前选中的节点配置
  • 详情:

    选中指点节点(将指点节点设置成当前选中状态)

    TIP

    editorService.select只是设置了编辑器的选中状态,并没有设置画布的选中状态,所以根据实际情况可以调用stage.select来设置画布的选中态

  • 示例:

js
import { editorService } from "@tmagic/editor";

editorService.select("text_123");
editorService.get("stage")?.select("text_123");

multiSelect

  • 参数:

    • {(number | string)[]} ids 需要选中的节点ID集合
  • 返回:

    • {Promise<void>}
  • 详情:

    选中多个节点

    TIP

    editorService.multiSelect只是设置了编辑器的选中状态,并没有设置画布的选中状态,所以根据实际情况可以调用stage.multiSelect来设置画布的选中态

  • 示例:

js
import { editorService } from "@tmagic/editor";

editorService.multiSelect(["text_123", "button_123"]);
editorService.get("stage")?.multiSelect(["text_123", "button_123"]);

selectNextNode

  • 返回:

    • {Promise<MNode | null>} 选中后的节点配置
  • 详情:

    选中当前节点同层级(同一父节点)的下一个节点,已经是最后一个时回到第一个

selectNextPage

  • 返回:

    • {Promise<MNode>} 选中后的页面配置
  • 详情:

    选中下一页,已经是最后一页时回到第一页

selectRoot

  • 返回:

    • {void}
  • 详情:

    选中根节点(root),同时清空当前选中的页面、父节点、画布及高亮节点

highlight

  • 扩展支持

  • 参数:

    • {number | string | MNode} config 需要高亮的节点或节点ID
  • 返回:

    • {Promise<void>}
  • 详情:

    高亮指定节点

  • 示例:

js
import { editorService } from "@tmagic/editor";

editorService.highlight("text_123");

doAdd

  • 扩展支持

  • 参数:

    • {MNode} node 新组件节点

    • {MContainer} parent 指定的容器节点

  • 返回:

    • {Promise<MNode>} 新增的组件
  • 详情:

    往指定的容器中添加组件

add

  • 扩展支持

  • 参数:

    • {MNode | MNode[]} node 新组件节点配置或多个节点集合

    • {MContainer} parent 指定的容器组件节点配置,如果不设置,默认为当前选中的组件的父节点

    • {Object} options 可选配置

      • {boolean} doNotSelect 添加后是否不更新当前选中节点(默认 false,添加后会选中新增的节点)
      • {boolean} doNotSwitchPage 添加后是否不切换当前页面(默认 false;新增页面 / 跨页新增时为 true 会跳过会引发页面切换的选中操作)
      • {boolean} doNotPushHistory 是否不写入历史记录(默认 false)
      • {string} historyDescription 见历史记录相关 options
      • {HistoryOpSource} historySource 见历史记录相关 options
  • 返回:

    • {Promise<MNode | MNode[]>} 新增的组件或组件集合
  • 详情:

    往指定的容器或当前容器中添加组件

    TIP

    doAdd的区别:

    add可以支持一次添加多个组件,add是通过调用doAdd来最终实现添加的。

    编辑器内部添加组件都是调用add来实现的,add除了添加操作外,还会记录历史堆栈,还会更新编辑中相关的状态,而doAdd就仅仅是完成添加的行为

doRemove

  • 扩展支持

  • 参数:

    • {MNode} node 要删除的节点
    • {Object} options 可选配置
      • {boolean} doNotSelect 删除后是否不更新当前选中节点(默认 false)
      • {boolean} doNotSwitchPage 删除后是否不切换当前页面(默认 false;删除页面 / 页面片段时为 true 会跳过自动切换到首个剩余页面)
  • 返回:

    • {Promise<void>}
  • 详情:

    删除指定的组件或者页面

    TIP

    无论是否传入 doNotSelect / doNotSwitchPage,当被删除节点在当前选中列表中时,state 都会自动移除该节点的引用;当被删除的正好是当前页面时,state.page 也会同步清空,避免持有已删除节点

remove

  • 扩展支持

  • 参数:

    • {MNode | MNode[])} node 要删除的节点或节点集合
    • {Object} options 可选配置
      • {boolean} doNotSelect 删除后是否不更新当前选中节点(默认 false,删除后会选中父节点或首个页面)
      • {boolean} doNotSwitchPage 删除后是否不切换当前页面(默认 false;删除页面 / 页面片段时为 true 会跳过自动切换到首个剩余页面)
      • {boolean} doNotPushHistory 是否不写入历史记录(默认 false)
      • {string} historyDescription 见历史记录相关 options
      • {HistoryOpSource} historySource 见历史记录相关 options
  • 返回:

    • {Promise<void>}
  • 详情:

    删除指定的组件或者页面或组件集合

    TIP

    doRemove的区别:

    remove可以支持一次删除多个组件,remove是通过调用doRemove来最终实现删除的。

    编辑器内部删除组件都是调用remove来实现的,remove除了删除操作外,还会记录历史堆。

doUpdate

  • 扩展支持

  • 参数:

    • {MNode} config 新的节点
    • {Object} data 可选配置
      • {ChangeRecord[]} changeRecords 变更记录
  • 返回:

    • {Promise<{ newNode: MNode; oldNode: MNode; changeRecords?: ChangeRecord[] }>} 更新前后的节点信息
    查看 ChangeRecord 类型定义
    ts
    export interface ChangeRecord {
      propPath?: string;
      value: any;
    }
  • 详情:

    更新节点

    TIP

    节点中应该要有id,不然不知道要更新哪个节点

    当被更新节点正好在当前选中列表中时,state 会自动同步到新的节点引用,无需调用方处理

    当被更新节点正好是当前页面时,state.page 也会同步到新的节点引用;更新非当前页面(不同 ID)时不会把编辑器切到该页

update

  • 扩展支持

  • 参数:

    • {MNode | MNode[]} config 新的节点或节点集合
    • {Object} data 可选配置
      • {ChangeRecord[]} changeRecords 单节点 form 端变更记录(多节点场景下被忽略,使用 changeRecordList
      • {ChangeRecord[][]} changeRecordList 多节点 form 端变更记录列表,按 config 数组同序对应每个节点;优先级高于 changeRecords
      • {boolean} doNotPushHistory 是否不写入历史记录(默认 false)
      • {string} historyDescription 见历史记录相关 options
      • {HistoryOpSource} historySource 见历史记录相关 options
    查看 ChangeRecord 类型定义
    ts
    export interface ChangeRecord {
      propPath?: string;
      value: any;
    }
  • 返回:

    • {Promise<MNode | MNode[]>} 新的节点或节点集合
  • 详情:

    更新单个或多个节点

    TIP

    doUpdate的区别:

    update可以支持一次更新多个组件,update是通过调用doUpdate来最终实现更新的。

    编辑器内部更新组件都是调用update来实现的,update除了更新操作外,还会记录历史堆,还会更新代码块关系链。

    TIP

    多节点场景必须使用 changeRecordList:每个节点应保留自己独立的 records,不能把多个节点的 records 合并到同一个 changeRecords 数组里,否则 doUpdate / 依赖收集 / 历史回放都会按错误的 propPath 处理。

    写入历史时,每个节点的 records 会单独保存到 updatedItems[i].changeRecords;撤销/重做时若有 records,则仅按 propPath 局部更新对应字段,避免整节点替换冲掉同节点上的其它无关变更;缺省 才退化为整节点替换(如内部 sort / moveLayer / 拖动等纯快照场景)。

sort

  • 扩展支持

  • 参数:

    • { 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]

    用于流式布局下的组件拖动更新

copy

  • 扩展支持

  • 参数:

    • {MNode | MNode[]} config 需要复制的节点或节点集合
  • 返回:

    • {void}
  • 详情:

复制组件节点或节点集合

通过storageService.setItem,将组件节点配置存储到localStorage中

copyWithRelated

  • 参数:

    • {MNode | MNode[]} config 需要复制的节点或节点集合
    • {TargetOptions} collectorOptions 可选的依赖收集器配置
  • 返回:

    • {void}
  • 详情:

    复制节点时会同时收集组件关联的依赖(如 dataSource、codeBlock 等),并一起存储到 localStorage 中,便于粘贴时一起带入

doPaste

粘贴前置操作:返回分配了新id以及校准了坐标的配置

paste

  • 扩展支持

  • 参数:

    • {PastePosition} position 粘贴的坐标
    查看 PastePosition 类型定义
    ts
    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
  • 返回:

    • {Promise<MNode | MNode[]>} 添加后的组件节点配置
  • 详情:

粘贴组件节点或节点集合

通过storageService.getItem,从localStorage中获取节点,然后添加到当前容器中

doAlignCenter

  • 扩展支持

  • 参数:

    • {MNode} config 需要居中的组件
  • 返回:

    • {Promise<MNode>}
  • 详情:

    水平居中组件节点,仅在流式布局下有效

    WARNING

    仅是计算出left,并未更新到编辑器中

alignCenter

  • 扩展支持

  • 参数:

    • {MNode | MNode[]} config 需要居中的组件或者组件集合
    • {Object} options 可选配置
      • {boolean} doNotSelect 居中后是否不更新当前选中节点(默认 false)
      • {boolean} doNotSwitchPage 居中后是否不切换当前页面(居中只更新节点 style,方法内为空操作;保留以与其它 DSL 操作 API 一致)
      • {boolean} doNotPushHistory 是否不写入历史记录(默认 false)
      • {string} historyDescription 见历史记录相关 options
      • {HistoryOpSource} historySource 见历史记录相关 options
  • 返回:

    • {Promise<MNode | MNode[]>}
  • 详情:

水平居中组件或者组件集合,仅在流式布局下有效

TIP

doAlignCenter的区别:

alignCenter可以支持一次水平居中多个组件,alignCenter是通过调用doAlignCenter来获取到已设置好水平居中的位置信息的节点,然后调用update更新。

moveLayer

  • 扩展支持

  • 参数:

  • 返回:

    • {Promise<void>}
  • 详情:

    移动当前选中节点位置

    用于实现上移一层、下移一层、置顶、置底

moveToContainer

  • 扩展支持

  • 参数:

    • {MNode} config 需要移动的节点
    • {string | number} targetId 容器ID
    • {Object} options 可选配置
      • {boolean} doNotSelect 移动后是否不更新当前选中节点(默认 false)
      • {boolean} doNotSwitchPage 移动后是否不切换当前页面(默认 false;目标容器位于其它页面时为 true 会跳过自动选中以避免页面切换)
      • {boolean} doNotPushHistory 是否不写入历史记录(默认 false)
      • {string} historyDescription 见历史记录相关 options
      • {HistoryOpSource} historySource 见历史记录相关 options
  • 返回:

    • Promise<MNode | undefined>
  • 详情:

    移动到指定容器中

dragTo

  • 参数:

    • {MNode | MNode[]} config 需要拖拽的节点或节点集合
    • {MContainer} targetParent 目标父容器
    • {number} targetIndex 目标位置索引
    • {Object} options 可选配置
  • 返回:

    • {Promise<void>}
  • 详情:

    将节点(支持多选)拖拽到目标容器的指定位置,会自动处理跨容器布局切换并记录历史

undo

  • 扩展支持

  • 返回:

    • {Promise<StepValue | null>}
    查看 StepValue 及关联类型定义
    ts
    export interface StepValue {
      /** 页面信息 */
      data: { name: string; id: Id };
      opType: HistoryOpType;
      /** 操作前选中的节点 ID,用于撤销后恢复选择状态 */
      selectedBefore: Id[];
      /** 操作后选中的节点 ID,用于重做后恢复选择状态 */
      selectedAfter: Id[];
      modifiedNodeIds: Map<Id, Id>;
      /** opType 'add': 新增的节点 */
      nodes?: MNode[];
      /** opType 'add': 父节点 ID */
      parentId?: Id;
      /** opType 'add': 每个新增节点在父节点 items 中的索引 */
      indexMap?: Record<string, number>;
      /** opType 'remove': 被删除的节点及其位置信息 */
      removedItems?: { node: MNode; parentId: Id; index: number }[];
      /**
       * opType 'update': 变更前后的节点快照
       *
       * `changeRecords` 来自 form 端的 propPath/value 列表,撤销/重做时只对这些 propPath 做局部更新;
       * 缺省(未传 / 空数组)才退化为整节点替换。
       */
      updatedItems?: { oldNode: MNode; newNode: MNode; changeRecords?: ChangeRecord[] }[];
      /**
       * 调用方可选传入的人类可读描述(如「调整按钮颜色」),用于历史面板展示。
       * 不影响 undo/redo 行为;缺省时面板会根据节点 / propPath 自动生成描述。
       */
      historyDescription?: string;
      /**
       * 操作途径:标记本次变更由哪条交互入口触发,取值见 {@link HistoryOpSource}
       * (画布 / 树面板 / 组件面板 / 配置面板 / 源码编辑器 / 右键菜单 / 工具栏 / 快捷键 / 回滚 / 接口 等)。
       * 仅用于历史面板展示与业务埋点,不影响 undo/redo 行为;缺省时面板视为「未知」。
       */
      source?: HistoryOpSource;
      /**
       * 入栈时间戳(毫秒)。在 historyService.push 时自动写入(若调用方未指定),仅用于历史面板展示。
       */
      timestamp?: number;
    }
    ts
    export type HistoryOpType = 'add' | 'remove' | 'update';
    ts
    /**
     * 历史记录的「操作途径」——标记本次变更由哪条交互入口触发,仅用于历史面板展示 / 业务埋点,
     * 不影响 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 =
      | 'stage'
      | 'tree'
      | 'component-panel'
      | 'props'
      | 'code'
      | 'stage-contextmenu'
      | 'tree-contextmenu'
      | 'toolbar'
      | 'shortcut'
      | 'rollback'
      | 'api'
      | 'ai'
      | 'unknown'
      | (string & {});
    ts
    export type Id = string | number;
  • 详情:

    撤销当前操作

redo

  • 扩展支持

  • 返回:

    • {Promise<StepValue | null>}
    查看 StepValue 及关联类型定义
    ts
    export interface StepValue {
      /** 页面信息 */
      data: { name: string; id: Id };
      opType: HistoryOpType;
      /** 操作前选中的节点 ID,用于撤销后恢复选择状态 */
      selectedBefore: Id[];
      /** 操作后选中的节点 ID,用于重做后恢复选择状态 */
      selectedAfter: Id[];
      modifiedNodeIds: Map<Id, Id>;
      /** opType 'add': 新增的节点 */
      nodes?: MNode[];
      /** opType 'add': 父节点 ID */
      parentId?: Id;
      /** opType 'add': 每个新增节点在父节点 items 中的索引 */
      indexMap?: Record<string, number>;
      /** opType 'remove': 被删除的节点及其位置信息 */
      removedItems?: { node: MNode; parentId: Id; index: number }[];
      /**
       * opType 'update': 变更前后的节点快照
       *
       * `changeRecords` 来自 form 端的 propPath/value 列表,撤销/重做时只对这些 propPath 做局部更新;
       * 缺省(未传 / 空数组)才退化为整节点替换。
       */
      updatedItems?: { oldNode: MNode; newNode: MNode; changeRecords?: ChangeRecord[] }[];
      /**
       * 调用方可选传入的人类可读描述(如「调整按钮颜色」),用于历史面板展示。
       * 不影响 undo/redo 行为;缺省时面板会根据节点 / propPath 自动生成描述。
       */
      historyDescription?: string;
      /**
       * 操作途径:标记本次变更由哪条交互入口触发,取值见 {@link HistoryOpSource}
       * (画布 / 树面板 / 组件面板 / 配置面板 / 源码编辑器 / 右键菜单 / 工具栏 / 快捷键 / 回滚 / 接口 等)。
       * 仅用于历史面板展示与业务埋点,不影响 undo/redo 行为;缺省时面板视为「未知」。
       */
      source?: HistoryOpSource;
      /**
       * 入栈时间戳(毫秒)。在 historyService.push 时自动写入(若调用方未指定),仅用于历史面板展示。
       */
      timestamp?: number;
    }
    ts
    export type HistoryOpType = 'add' | 'remove' | 'update';
    ts
    /**
     * 历史记录的「操作途径」——标记本次变更由哪条交互入口触发,仅用于历史面板展示 / 业务埋点,
     * 不影响 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 =
      | 'stage'
      | 'tree'
      | 'component-panel'
      | 'props'
      | 'code'
      | 'stage-contextmenu'
      | 'tree-contextmenu'
      | 'toolbar'
      | 'shortcut'
      | 'rollback'
      | 'api'
      | 'ai'
      | 'unknown'
      | (string & {});
    ts
    export type Id = string | number;
  • 详情:

    恢复到下一步

move

  • 扩展支持

  • 参数:

  • 返回:

    • {Promise<void>}
  • 详情:

    更新当前选中组件位置,通常用于键盘上下左右快捷键操作

resetModifiedNodeId

  • 详情:

重置当前记录的修改过的节点id记录,通常用于保存之后

resetState

  • 详情:

清空state

destroy

  • 详情:

    销毁editorService

    移除所有事件监听,清空state,移除所有插件

usePlugin

  • 详情:

    usePlugin支持灵活细致的扩展, 上述方法中标记有扩展支持: 是的方法都支持使用usePlugin扩展

每个支持扩展的方法都支持定制before、after两个hook来干预原有方法的行为,before可以用于修改传入参数,after可以用于修改返回的值

  • 示例:
js
import { editorService } from "@tmagic/editor";

editorService.usePlugin({
  // 添加组件的时候设置一个添加时间
  beforeDoAdd: (config, parent) => {
    config.addTime = new Date().getTime();

    return [config, parent];
  },
});

removeAllPlugins

  • 详情:

删掉当前设置的所有扩展

Powered by 腾讯视频会员平台技术中心