Editor组件 props
modelValue/v-model
详情:
页面初始值
默认值:
{}类型:
MApp[]查看 MApp 及关联类型定义
tsexport interface MApp extends MComponent { /** App页面类型,app作为整个结构的根节点;有且只有一个 */ type: NodeType.ROOT; /** */ items: (MPage | MPageFragment)[]; /** 代码块 */ codeBlocks?: CodeBlockDSL; dataSources?: DataSourceSchema[]; dataSourceDeps?: DataSourceDeps; dataSourceCondDeps?: DataSourceDeps; dataSourceMethodDeps?: DataSourceDeps; }tsexport 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; }tsexport enum NodeType { /** 容器 */ CONTAINER = 'container', /** 页面 */ PAGE = 'page', /** 根类型 */ ROOT = 'app', /** 页面片 */ PAGE_FRAGMENT = 'page-fragment', }tsexport interface MPage extends MContainer { /** 页面类型 */ type: NodeType.PAGE; }tsexport interface MPageFragment extends MContainer { /** 页面类型 */ type: NodeType.PAGE_FRAGMENT; }tsexport interface CodeBlockDSL { [id: Id]: CodeBlockContent; }tsexport interface DataSourceSchema { /** 数据源类型,根据类型来实例化;例如http则使用new HttpDataSource */ type: string; /** 实体ID */ id: string; /** 实体名称,用于关联时展示 */ title?: string; /** 实体描述,鼠标hover时展示 */ description?: string; /** 字段列表 */ fields: DataSchema[]; /** 方法列表 */ methods: CodeBlockContent[]; /** mock数据 */ mocks?: MockSchema[]; /** 事件 */ events: EventConfig[]; /** 不执行init的环境 */ disabledInitInJsEngine?: (JsEngine | string)[]; /** 扩展字段 */ [key: string]: any; }tsexport interface DataSourceDeps { [dataSourceId: string | number]: DepData; }示例:
<template>
<m-editor v-model="dsl"></m-editor>
</template>
<script setup>
import { ref } from 'Vue';
const dsl = ref({
type: 'app',
id: 'app_1',
items: [
{
type: 'page',
id: 'page_1',
items: [
{
type: 'text',
id: 'text_1',
text: '文本'
},
],
},
],
});
</script>componentGroupList
详情:
左侧面板中的组件列表
默认值:
[]类型:
ComponentGroup[]查看 ComponentGroup 及关联类型定义
tsexport interface ComponentGroup { /** 显示文案 */ title: string; /** 组内列表 */ items: ComponentItem[]; }tsexport interface ComponentItem { /** 显示文案 */ text: string; /** 详情,用于tooltip */ desc?: string; /** 组件类型 */ type: string; /** Vue组件或url */ icon?: string | Component<{}, {}, any>; /** 新增组件时需要透传到组价节点上的数据 */ data?: { [key: string]: any; }; }
TIP
icon使用的是element-plus icon
也可直接使用url,例如
{
icon: 'https://vfiles.gtimg.cn/vupload/20220614/9cc3091655207317835.png'
}url支持相对路径或者绝对路径,例如
{
icon: './icon.png'
}
{
icon: '/icon.png'
}WARNING
请注意如果只是文件名的话是不行的,会被认为是css class
- 示例:
<template>
<m-editor :component-group-list="componentGroupList"></m-editor>
</template>
<script setup>
import { ref, markRaw } from 'Vue';
import { FolderOpened, SwitchButton, Tickets } from '@element-plus/icons-vue';
const componentGroupList = ref([
{
title: '容器',
items: [
{
icon: markRaw(FolderOpened),
text: '组',
type: 'container',
},
],
},
{
title: '基础组件',
items: [
{
icon: markRaw(Tickets),
text: '文本',
type: 'text',
},
{
icon: markRaw(SwitchButton),
text: '按钮',
type: 'button',
},
],
},
]);
</script>WARNING
此配置仅在sidebar中配置了'component-list'时有效
datasourceList
详情:
左侧数据源面板中可新增的自定义数据源列表
默认值:
[]类型:
DatasourceTypeOption[]查看 DatasourceTypeOption 类型定义
ts/** 可新增的数据源类型选项 */ export interface DatasourceTypeOption { /** 数据源类型 */ type: string; /** 数据源名称 */ text: string; }示例:
<template>
<m-editor :datasource-list="datasourceTypeList"></m-editor>
</template>
<script setup>
import { ref } from 'Vue';
const datasourceTypeList = ref([
{
type: 'http',
text: 'Http数据源'
}
])
</script>TIP
系统默认已提供了base,http两种基础数据源,此处配置的使用者新增的数据源
sidebar
详情:
左侧面板,目前只支持type: 'tabs';
默认值:
{
type: 'tabs',
status: '组件',
items: ['component-list', 'layer', 'code-block'],
}类型:
SideBarData查看 SideBarData 及关联类型定义
ts/** 工具栏 */ export interface SideBarData { /** 容器类型 */ type: 'tabs'; /** 默认激活的内容 */ status: string; /** panel列表 */ items: SideItem[]; }ts/** * component-list: 组件列表 * layer: 已选组件树 * code-block: 代码块 */ export type SideItem = `${SideItemKey}` | SideComponent;tsexport enum SideItemKey { COMPONENT_LIST = 'component-list', LAYER = 'layer', CODE_BLOCK = 'code-block', DATA_SOURCE = 'data-source', }tsexport interface SideComponent extends MenuComponent { /** 显示文案 */ text: string; /** tab样式 */ tabStyle?: string | Record<string, any>; /** vue组件或url */ icon?: any; /** slide 唯一标识 key */ $key: string; /** 是否可以将面板拖出,默认为true */ draggable?: boolean; /** 点击切换tab前调用,返回false阻止切换 */ beforeClick?: (config: SideComponent) => boolean | Promise<boolean>; /** 组件扩展参数 */ boxComponentConfig?: { /** Vue3组件 */ component?: any; /** 传入组件的props对象 */ props?: Record<string, any>; }; }tsexport interface MenuComponent { type: 'component'; /** Vue3组件 */ component: any; /** 传入组件的props对象 */ props?: Record<string, any>; /** 组件监听的事件对象,如:{ click: () => { console.log('click'); } } */ listeners?: Record<string, Function>; slots?: Record<string, any>; /** 是否显示,默认为true */ className?: string; display?: boolean | ((data: Services) => Promise<boolean> | boolean); [key: string]: any; }tsexport interface Services { editorService: EditorService; historyService: HistoryService; storageService: StorageService; eventsService: EventsService; propsService: PropsService; componentListService: ComponentListService; uiService: UiService; codeBlockService: CodeBlockService; depService: DepService; dataSourceService: DataSourceService; keybindingService: KeybindingService; stageOverlayService: StageOverlayService; }示例:
<template>
<m-editor :sidebar="sidebar"></m-editor>
</template>
<script setup>
import { ref, markRaw } from 'Vue';
import { List } from '@element-plus/icons-vue';
import ModListPanel from '../components/sidebars/ModListPanel.vue';
const sidebar = ref({
type: 'tabs',
status: '组件',
items: [
'component-list',
'layer',
{
type: 'component',
icon: markRaw(List),
component: markRaw(ModListPanel),
text: '模块',
},
],
});
</script>TIP
icon使用的是element-plus icon
也可直接使用url,例如
{
icon: 'https://vfiles.gtimg.cn/vupload/20220614/9cc3091655207317835.png'
}menu
详情:
顶部工具栏
系统提供了几个常用功能:
'/' | 'delete' | 'undo' | 'redo' | 'zoom-in' | 'zoom-out' | 'zoom' | 'guides' | 'rule' | 'scale-to-original' | 'scale-to-fit' | 'history-list''/': 分隔符
'delete': 删除按钮
'undo': 撤销按钮
'redo': 恢复按钮
'zoom-in': 放大按钮
'zoom-out': 缩小按钮
'zoom': 缩放(zoom-in', 'zoom-out', 'scale-to-original', 'scale-to-fit' 的集合)
'guides': 显示隐藏参考线
'rule': 显示隐藏标尺
'scale-to-original': 缩放到实际大小
'scale-to-fit': 缩放以适应
'history-list': 历史记录面板(按 页面 / 数据源 / 代码块 三个 tab 展示操作历史,相邻同目标修改自动合并,支持点击跳转、回到初始状态、单步回滚及差异对比,详见历史记录面板)
默认值:
{ left: [], center: [], right: [] }类型:
MenuBarData查看 MenuBarData 及关联类型定义
ts/** 工具栏 */ export interface MenuBarData { /** 顶部工具栏左边项 */ [ColumnLayout.LEFT]?: MenuItem[]; /** 顶部工具栏中间项 */ [ColumnLayout.CENTER]?: MenuItem[]; /** 顶部工具栏右边项 */ [ColumnLayout.RIGHT]?: MenuItem[]; }tsexport enum ColumnLayout { LEFT = 'left', CENTER = 'center', RIGHT = 'right', }tsexport type MenuItem = | '/' | 'delete' | 'undo' | 'redo' | 'zoom' | 'zoom-in' | 'zoom-out' | 'guides' | 'rule' | 'scale-to-original' | 'scale-to-fit' | 'history-list' | MenuButton | MenuComponent | string;ts/** * 菜单按钮 */ export interface MenuButton { /** * 按钮类型 * button: 只有文字不带边框的按钮 * text: 纯文本 * divider: 分割线 * dropdown: 下拉菜单 */ type: 'button' | 'text' | 'divider' | 'dropdown'; /** 当type为divider时有效,分割线方向, 默认vertical */ direction?: 'horizontal' | 'vertical'; /** 展示的文案 */ text?: string; /** 鼠标悬浮是显示的气泡中的文案 */ tooltip?: string; /** Vue组件或url */ icon?: string | Component<{}, {}, any>; /** 是否置灰,默认为false */ disabled?: boolean | ((data: Services) => boolean); /** 是否显示,默认为true */ display?: boolean | ((data: Services) => boolean); /** type为button/dropdown时点击运行的方法 */ handler?: (data: Services, event: MouseEvent) => Promise<any> | any; className?: string; /** type为dropdown时,下拉的菜单列表, 或者有子菜单时 */ items?: MenuButton[]; /** 唯一标识,用于高亮 */ id?: string | number; }tsexport interface MenuComponent { type: 'component'; /** Vue3组件 */ component: any; /** 传入组件的props对象 */ props?: Record<string, any>; /** 组件监听的事件对象,如:{ click: () => { console.log('click'); } } */ listeners?: Record<string, Function>; slots?: Record<string, any>; /** 是否显示,默认为true */ className?: string; display?: boolean | ((data: Services) => Promise<boolean> | boolean); [key: string]: any; }tsexport interface Services { editorService: EditorService; historyService: HistoryService; storageService: StorageService; eventsService: EventsService; propsService: PropsService; componentListService: ComponentListService; uiService: UiService; codeBlockService: CodeBlockService; depService: DepService; dataSourceService: DataSourceService; keybindingService: KeybindingService; stageOverlayService: StageOverlayService; }示例:
<template>
<m-editor :menu="menu"></m-editor>
</template>
<script setup>
import { ref, markRaw, toRaw } from 'Vue';
import { ArrowLeft, Coin } from '@element-plus/icons-vue';
const menu = ref({
left: [
{
type: 'button',
icon: markRaw(ArrowLeft),
tooltip: '返回',
},
'/',
{
type: 'text',
text: '.temp',
},
],
center: ['delete', 'undo', 'redo', 'zoom'],
right: [
{
type: 'button',
text: '保存',
icon: markRaw(Coin),
disabled: true,
handler: ({ editorService }) => {
console.log(toRaw(editorService.get('root'));
}),
},
],
})
</script>layerContentMenu
详情: 扩展已选组件(组件树)右键菜单
默认值:
[]类型:
(MenuButton | MenuComponent)[]查看 MenuButton / MenuComponent 及关联类型定义
ts/** * 菜单按钮 */ export interface MenuButton { /** * 按钮类型 * button: 只有文字不带边框的按钮 * text: 纯文本 * divider: 分割线 * dropdown: 下拉菜单 */ type: 'button' | 'text' | 'divider' | 'dropdown'; /** 当type为divider时有效,分割线方向, 默认vertical */ direction?: 'horizontal' | 'vertical'; /** 展示的文案 */ text?: string; /** 鼠标悬浮是显示的气泡中的文案 */ tooltip?: string; /** Vue组件或url */ icon?: string | Component<{}, {}, any>; /** 是否置灰,默认为false */ disabled?: boolean | ((data: Services) => boolean); /** 是否显示,默认为true */ display?: boolean | ((data: Services) => boolean); /** type为button/dropdown时点击运行的方法 */ handler?: (data: Services, event: MouseEvent) => Promise<any> | any; className?: string; /** type为dropdown时,下拉的菜单列表, 或者有子菜单时 */ items?: MenuButton[]; /** 唯一标识,用于高亮 */ id?: string | number; }tsexport interface MenuComponent { type: 'component'; /** Vue3组件 */ component: any; /** 传入组件的props对象 */ props?: Record<string, any>; /** 组件监听的事件对象,如:{ click: () => { console.log('click'); } } */ listeners?: Record<string, Function>; slots?: Record<string, any>; /** 是否显示,默认为true */ className?: string; display?: boolean | ((data: Services) => Promise<boolean> | boolean); [key: string]: any; }tsexport interface Services { editorService: EditorService; historyService: HistoryService; storageService: StorageService; eventsService: EventsService; propsService: PropsService; componentListService: ComponentListService; uiService: UiService; codeBlockService: CodeBlockService; depService: DepService; dataSourceService: DataSourceService; keybindingService: KeybindingService; stageOverlayService: StageOverlayService; }示例:
<template>
<m-editor :layer-content-menu="layerContentMenu"></m-editor>
</template>
<script setup>
import { ref, toRaw } from 'Vue';
import { Upload } from '@element-plus/icons-vue';
const layerContentMenu = ref([
{
{
type: 'button',
icon: toRow(Upload),
text: '导出',
handler: () => {
console.log('export')
},
},
},
]);
</script>stageContentMenu
详情: 扩展stage(画布区域)右键菜单
默认值:
[]类型:
(MenuButton | MenuComponent)[]已在上面 layerContentMenu 段落展开过相同类型,参考即可。
示例:
<template>
<m-editor :stage-content-menu="stageContentMenu"></m-editor>
</template>
<script setup>
import { ref, toRaw } from 'Vue';
import { Upload } from '@element-plus/icons-vue';
const stageContentMenu = ref([
{
{
type: 'button',
icon: toRow(Upload),
text: '导出',
handler: () => {
console.log('export')
},
},
},
]);
</script>runtimeUrl
详情:
runtime的HTML地址
在编辑器画布中渲染组件是使用iframe实现,runtimeUrl就是配置在iframe上的src属性
默认值:
undefined类型:
string示例:
<template>
<m-editor
runtime-url="https://tencent.github.io/tmagic-editor/playground/runtime/vue/playground/index.html"
></m-editor>
</template>render
详情:
中间工作区域中画布渲染的内容,通常是通过解析modelValue来渲染出DOM,return的DOM结构需要有一个根节点。
TIP
runtimeUrl与render有且只需要配置一个
默认值:
undefined类型: (stage: StageCore) =>
HTMLDivElement| Promise<HTMLDivElement>示例:
<template>
<m-editor
:render="renderFunction"
></m-editor>
</template>
<script setup>
const renderFunction = async (stage) => {
const { iframe } = stage.renderer;
if (!iframe) throw new Error('iframe 未创建');
return iframe.contentDocument.createElement('div');
}
</script>renderType
详情:
是用iframe渲染还是直接渲染
默认值:
iframe类型:
string'iframe' | 'native'
示例:
<template>
<m-editor render-type="native"></m-editor>
</template>autoScrollIntoView
详情:
选中组件时,是否自动滚动该组件到可视区域
默认值:
undefined类型:
boolean示例:
<template>
<m-editor :auto-scroll-intoView="true"></m-editor>
</template>propsConfigs
详情:
组件的属性配置表单的dsl
TIP
该属性最终会设置到propsService中,所以也可直接调用propsService.setPropsConfigs()方法来配置
当选中一个组件时,会根据组件的type值从propsConfigs中获取对应的表单的dsl,并在属性面板中渲染出来
TIP
获取表单的dsl后实际上还会经过propsService.fillConfig()方法来处理,用于添加公共配置
默认值:
{}类型:
Record<string, FormConfig>查看 FormConfig 及关联类型定义
tsexport type FormConfig<T = never> = FormItemConfig<T>[];tsexport type FormItemConfig<T = never> = ChildConfig<T> | DynamicTypeConfig | EditorChildConfig<T> | T;tsexport type ChildConfig<T = never> = | ContainerCommonConfig<T> | TabConfig<T> | RowConfig<T> | FieldsetConfig<T> | PanelConfig<T> | TableConfig | GroupListConfig<T> | StepConfig<T> | DisplayConfig | TextConfig | NumberConfig | NumberRangeConfig | HiddenConfig | LinkConfig<T> | DaterangeConfig | TimerangeConfig | SelectConfig | CascaderConfig | HtmlField | DateConfig | ColorPickConfig | TimeConfig | DateTimeConfig | CheckboxConfig | SwitchConfig | RadioGroupConfig | CheckboxGroupConfig | TextareaConfig | DynamicFieldConfig | ComponentConfig | FlexLayoutConfig<T>;tsexport interface DynamicTypeConfig extends FormItem { type: TypeFunction; [key: string]: any; }tsexport interface FormItem { /** vnode的key值,默认是遍历数组时的index */ __key?: string | number; /** 表单域标签的的宽度,例如 '50px'。支持 auto。 */ labelWidth?: string | number; /** label 标签的title属性 */ labelTitle?: string; className?: string; /** 字段名 */ name?: string | number; /** 额外的提示信息,和 help 类似,当提示文案同时出现时,可以使用这个。 */ extra?: string | FilterFunction<string>; /** 配置提示信息 */ tooltip?: ToolTipConfigType | FilterFunction<ToolTipConfigType>; /** 是否置灰 */ disabled?: boolean | FilterFunction; /** 使用表单中的值作为key,例如配置了text,则使用model.text作为key */ key?: string; /** 是否显示 */ display?: boolean | 'expand' | FilterFunction<boolean | 'expand'>; /** 值发生改变时调用的方法 */ onChange?: OnChangeHandler; /** label 标签的文本 */ text?: string | FilterFunction<string>; /** 右侧感叹号 */ tip?: string; filter?: 'number' | OnChangeHandler; /** 是否去除首尾空格 */ trim?: boolean; /** 默认值 */ defaultValue?: any | DefaultValueFunction; /** 表单验证规则 */ rules?: Rule[]; extensible?: boolean; dynamicKey?: string; /** 是否需要显示`展开更多配置` */ expand?: boolean; style?: Record<string, any>; fieldStyle?: Record<string, any>; labelPosition?: 'top' | 'left' | 'right'; }示例:
<template>
<m-editor :props-configs="propsConfigs"></m-editor>
</template>
<script setup>
const propsConfigs = {
text: [
{
name: 'text',
text: '文本',
},
{
name: 'multiple',
text: '多行文本',
type: 'switch',
},
],
button: [
{
name: 'text',
text: '文本',
},
]
}
</script>propsValues
详情:
添加组件时的默认值
添加组件时,组件节点DSL的生成过程为,先从componentGroupList中items中item的data得到一个基础配置,然后再通过propsService.getPropsValue()方法,获取到propsValues中对应type的默认值,二者合并生成新增节点的DSL配置
TIP
该属性最终会设置到propsService中,所以也可直接调用propsService.setPropsValues()方法来配置
默认值:
{}类型:
Record<string, Object>示例:
<template>
<m-editor :props-values="propsValues"></m-editor>
</template>
<script setup>
const propsValues = {
text: {
text: '文本',
// 多行文本
multiple: true,
},
button: {
text: '按钮',
},
};
</script>eventMethodList
详情:
组件属性配置中事件tab中的事件名与动作的下拉选项列表
TIP
该属性最终会设置到eventsService中,所以也可直接调用eventsService.setEvents()与eventsService.setMethods()方法来配置
默认值:
{}类型:
Record<string, { events: EventOption[]; methods: EventOption[] }>查看 EventOption 类型定义
tsexport interface EventOption { label: string; value: string; }示例:
<template>
<m-editor :event-method-list="eventMethodList"></m-editor>
</template>
<script setup>
const eventMethodList = {
page: {
methods: [
{
label: '刷新',
value: 'refresh',
},
],
events: [
{
label: '加载',
value: 'load',
},
],
},
};
</script>datasourceValues
详情:
与
propsValues类似,新增数据源时的默认值TIP
该属性最终会设置到dataSourceService中,所以也可直接调用dataSourceService.setFormValue()方法来配置
默认值:
{}类型:
Record<string, Partial<DataSourceSchema>>查看 DataSourceSchema 及关联类型定义
tsexport interface DataSourceSchema { /** 数据源类型,根据类型来实例化;例如http则使用new HttpDataSource */ type: string; /** 实体ID */ id: string; /** 实体名称,用于关联时展示 */ title?: string; /** 实体描述,鼠标hover时展示 */ description?: string; /** 字段列表 */ fields: DataSchema[]; /** 方法列表 */ methods: CodeBlockContent[]; /** mock数据 */ mocks?: MockSchema[]; /** 事件 */ events: EventConfig[]; /** 不执行init的环境 */ disabledInitInJsEngine?: (JsEngine | string)[]; /** 扩展字段 */ [key: string]: any; }tsexport interface DataSchema { type?: DataSourceFieldType; /** 键名 */ name: string; /** 展示名称 */ title?: string; /** 实体描述,鼠标hover时展示 */ description?: string; /** 默认值 */ defaultValue?: any; /** 是否可用 */ enable?: boolean; /** type === 'object' || type === 'array' */ fields?: DataSchema[]; }tsexport interface MockSchema { /** 名称 */ title: string; /** 详细描述 */ description?: string; /** 是否启用,用于编辑器以外的runtime */ enable: boolean; /** 编辑器中使用使用此条数据,仅用于编辑器runtime中 */ useInEditor: boolean; /** mock数据 */ data: Record<string | number, any>; }tsexport interface CodeBlockContent { /** 代码块名称 */ name: string; /** 代码块内容 */ content: ((...args: any[]) => any) | Function; /** 参数定义 */ params: CodeParam[] | []; /** 注释 */ desc?: string; /** 扩展字段 */ [propName: string]: any; }tsexport interface CodeParam { /** 参数名 */ name: string; /** 扩展字段 */ [propName: string]: any; }tsexport interface EventConfig { /** 待触发的事件名称 */ name: string; /** 动作响应配置 */ actions: EventActionItem[]; }tsexport type JsEngine = 'browser' | 'hippy' | 'nodejs';示例:
<template>
<m-editor :datasource-values="datasourceValues"></m-editor>
</template>
<script setup>
const datasourceValues = {
'user-info': {
type: 'user-info',
title: '用户信息',
description: '用户信息',
fields: [
{
type: 'string',
name: 'nick',
title: '昵称',
defaultValue: '请登录',
enable: true,
},
]
},
};
</script>datasourceConfigs
详情:
与
propsConfigs类似,数据源的属性配置表单的dslTIP
该属性最终会设置到dataSourceService中,所以也可直接调用dataSourceService.setFormConfig()方法来配置
默认值:
{}类型:
Record<string, FormConfig>已在上面 propsConfigs 段落展开过
FormConfig类型定义,参考即可。示例:
<template>
<m-editor :datasource-configs="datasourceConfigs"></m-editor>
</template>
<script setup>
const datasourceConfigs = {
'user-info': [
{
type: 'select',
name: 'type',
text: '类型',
options: [
{ text: 'qq', value: 'qq'}
]
}
],
};
</script>datasourceEventMethodList
详情:
组件属性配置中事件tab中的事件名与动作的下拉选项列表
默认值:
{}
moveableOptions
详情:
画布中的选中框配置选项,使用的是moveable第三方库,可以用来控制组件在画布中是否能被拖动等行为
默认值:
{}类型:
((config: CustomizeMoveableOptionsCallbackConfig) => MoveableOptions) |MoveableOptions查看 CustomizeMoveableOptionsCallbackConfig 类型定义
tsexport interface CustomizeMoveableOptionsCallbackConfig { targetEl: HTMLElement | null; targetElId?: string; targetEls?: HTMLElement[]; targetElIds?: string[]; isMulti: boolean; document?: Document; }示例:
<template>
<m-editor :moveable-options="moveableOptions"></m-editor>
</template>
<script setup>
const moveableOptions = ({ targetId }) => {
const options = {};
const node = editorService.getNodeById(id);
if (!node) return options;
const isPage = node.type === 'page';
// 页面不允许拖动
options.draggable = !isPage;
options.resizable = !isPage
return options;
};
</script>defaultSelected
详情:
编辑器初始化后默认选中的组件节点id
默认值:
undefined类型:
string | number示例:
<template>
<m-editor :default-selected="defaultSelected"></m-editor>
</template>
<script setup>
import { ref } from 'vue';
const defaultSelected = ref('');
// 加载dsl后设置默认选中节点
getDsl().then(() => {
defaultSelected.value = 'xxx';
});
</script>canSelect
详情:
鼠标在画布点击时,当前坐标下的dom节点是否可以选中,当前坐标下的dom可能不止只有一个,当有多个时会遍历这些节点并调用canSelect方法进行判断,第一个返回true的dom节点将被选中
TIP
获取坐标下的节点是通过document.elementsFromPoint方法
默认值:
(el: HTMLElement) => Boolean(el.id)类型:
(el: HTMLElement) => boolean | Promise<boolean>示例:
<template>
<m-editor :can-select="canSelect"></m-editor>
</template>
<script setup>
// 只有dom id为纯数字时才可以被选中
const canSelect = (el) => /^\d+$/.test(el.id);
</script>isContainer
详情:
当组件拖动过程中停留在画布上超过 containerHighlightDuration 时长时,识别当前是否有容器
当停留超过containerHighlightDuration 时长时,会通过停留的坐标获取当前坐标下所有dom节点,然后遍历这些节点并通过isContainer方法判断,第一个返回true的节点将视为容器
TIP
获取坐标下的节点是通过document.elementsFromPoint方法
默认值:
(el: HTMLElement) => el.classList.contains('magic-ui-container')类型:
(el: HTMLDivElement) => boolean | Promise<boolean>;示例:
<template>
<m-editor :is-container="isContainer"></m-editor>
</template>
<script setup>
const canSelect = (el) => /^\d+$/.test(el.id);
const isContainer = (el) =>
canSelect(el) &&
(el.classList.contains('magic-ui-container') ||
el.classList.contains('magic-ui-pc-container') ||
el.classList.contains('magic-ui-page') ||
el.classList.contains('magic-ui-pop-content'));
</script>canDropIn
详情:
用于自定义判断当前正在拖动的源是否可以拖入目标节点内部。同时覆盖"组件树拖动"和"画布拖入"两类场景,通过第三个参数
scene区分;返回值有 3 种语义。scene 取值:
scene 触发场景 sourceIdstargetId'layer'"已选组件"面板组件树拖动 被拖动节点 id(单选时长度为 1) 目标节点 id 'stage-drag'画布上拖动已有组件 被拖动组件 id 列表(多选时为多个) 候选容器节点 id 'stage-add'从左侧组件列表拖入新组件到画布 始终为空数组(尚无 id,可仅依据 targetId判断)候选容器节点 id 返回值语义:
返回值 layer stage-drag stage-add false禁用 inner;同时禁用所有"target 子节点的 before/after"(这些位置等价于放入 target,避免被绕过) 阻止该容器被高亮命中 取消此次拖入 Id(string | number)将 inner 拖入目标重定向为该 id 对应的节点;与 false一致禁用所有"target 子节点的 before/after"高亮命中切换到该 id 对应元素,最终拖入到该节点 直接将组件添加到该 id 对应节点(layout 坐标也基于其 DOM 重新计算) true/void/undefined按原 targetId 正常拖入 同左 同左 scene取'stage-drag'或'stage-add'时该函数会被透传给StageCore的canDropIn,因此直接使用@tmagic/stage时同样生效TIP
- 可通过
editorService.getNodeById(id, false)把 id 还原为MNode以便基于业务字段(type、name等)做判断。 - 该函数为同步调用(拖动事件在浏览器中需要立即响应,不接受异步返回)。
- 重定向到一个不存在或非容器的目标 id 时会被忽略:layer/stage-add 场景会取消此次拖入;stage-drag 场景不会高亮。
- 可通过
默认值:
undefined类型:
(sourceIds: Id[], targetId: Id, scene: 'layer' | 'stage-drag' | 'stage-add') => Id | boolean | void示例 1:禁止某些组件拖入特定容器
<template>
<m-editor :can-drop-in="canDropIn"></m-editor>
</template>
<script setup>
import { editorService } from '@tmagic/editor';
// 禁止 button 类型的组件被拖入 list 容器内部,组件树拖动与画布拖入均生效
const canDropIn = (sourceIds, targetId, scene) => {
const targetNode = editorService.getNodeById(targetId, false);
if (targetNode?.type !== 'list') return true;
// 从组件列表新增组件时直接放行
if (scene === 'stage-add') return true;
return sourceIds.every((id) => {
const node = editorService.getNodeById(id, false);
return node?.type !== 'button';
});
};
</script>- 示例 2:将拖入"卡片外壳"重定向到"卡片内容"内层容器
<template>
<m-editor :can-drop-in="canDropIn"></m-editor>
</template>
<script setup>
import { editorService } from '@tmagic/editor';
// 当用户拖入到 card 节点时,自动改为放入其 card-content 内层容器
const canDropIn = (sourceIds, targetId) => {
const targetNode = editorService.getNodeById(targetId, false);
if (targetNode?.type !== 'card') return true;
const innerContent = targetNode.items?.find((item) => item.type === 'card-content');
return innerContent?.id ?? true;
};
</script>containerHighlightClassName
- 详情:
识别到容器后,会给其dom上添加的class
默认值:
'tmagic-stage-container-highlight'类型:
string
containerHighlightDuration
- 详情:
当组件拖动过程中停留在画布上超过 containerHighlightDuration 时长时,识别当前是否有容器
默认值:
800(单位为ms)类型:
number
containerHighlightType
- 详情:
在画布中,将组件拖入其他容器的方式
启动方式
default: 停留在画布上启动识别
alt: 按住alt键启动识别
其他值:不启动
默认值:
'default'类型:
'default' | 'alt' | ''
stageRect
详情:
画布的大小
TIP
该属性最终会设置到uiService中,所以也可直接调用uiService.set('stageRect', value)方法来配置
默认值:
{
width: 375,
height: 817,
}- 类型:
interface StageRect {
width: number;
height: number;
}codeOptions
详情:
编辑器中的代码编辑器配置
TIP
tmagic-editor中的所有代码编辑器都使用monaco-editor,详细配置请前往monaco-editor官网查看
默认值: ``{}
类型:
Object示例:
<template>
<m-editor :code-options="codeOptions"></m-editor>
</template>
<script setup>
const codeOptions = {
tabSize: 2,
fontSize: 16,
formatOnPaste: true,
}
</script>updateDragEl
- 详情:
当选中框与组件不贴合时,可以通过此方法进行调整
TIP
由于画布中组件是渲染在iframe中,而选中框是渲染在编辑器中,所以会导致两者的坐标系有差异,为了解决这个问题,在canSelect为true后会在编辑中创建一个位置大小与组件(target)一致的dom(el)
类型:
(el: HTMLElement | SVGElement, target: HTMLElement | SVGElement) => void默认值:
undefined示例:
<template>
<m-editor :update-drag-el="updateDragEl"></m-editor>
</template>
<script setup>
const updateDragEl = (el, target) => {
const node = editorStore.pop;
if (!node || !isPop(node)) {
return;
}
const { top, left } = target.getBoundingClientRect();
el.style.transform = 'none';
el.style.top = `${top}px`;
el.style.left = `${left}px`;
};disabledDragStart
- 详情:
禁用组件未选中情况下,按住鼠标直接拖动
类型:
boolean默认值:
false示例:
<template>
<m-editor :disabled-drag-start="true"></m-editor>
</template>disabledMultiSelect
- 详情:
禁止多选
类型:
boolean默认值:
false示例:
<template>
<m-editor :disabled-multi-select="true"></m-editor>
</template>alwaysMultiSelect
详情:
始终启用多选模式:开启后无需按住
Ctrl/Meta键,组件树和画布上点击即多选。 当disabledMultiSelect为true时本配置失效。类型:
boolean默认值:
false示例:
<template>
<m-editor :always-multi-select="true"></m-editor>
</template>guidesOptions
详情:
画布标尺和参考线的配置选项
默认值:
undefined类型:
Partial<GuidesOptions>示例:
<template>
<m-editor :guides-options="guidesOptions"></m-editor>
</template>
<script setup>
const guidesOptions = {
// 标尺刻度单位
unit: 1,
// 标尺背景色
backgroundColor: '#f0f0f0',
// 标尺文字颜色
textColor: '#333',
// 参考线颜色
lineColor: '#ff0000',
};
</script>disabledPageFragment
详情:
禁用页面片功能
页面片是可以在多个页面中复用的组件集合
默认值:
false类型:
boolean示例:
<template>
<m-editor :disabled-page-fragment="true"></m-editor>
</template>disabledFlashTip
详情:
禁用「非点击画布选中组件时的高亮闪烁提示」。
当组件不是通过点击画布选中(如从组件树、面包屑等外部方式选中)时,编辑器会在画布上对选中区域做一次高亮闪烁,帮助用户快速定位组件在画布中的位置。设置为
true可关闭该提示。注:选中页面(
magic-ui-page)时不会触发闪烁。默认值:
false类型:
boolean示例:
<template>
<m-editor :disabled-flash-tip="true"></m-editor>
</template>disabledStageOverlay
详情:
禁用双击在浮层中单独编辑选中组件的功能
启用时,双击组件可以在浮层中单独编辑,避免其他组件干扰
默认值:
false类型:
boolean示例:
<template>
<m-editor :disabled-stage-overlay="true"></m-editor>
</template>disabledShowSrc
详情:
禁用属性配置面板右下角"显示源码"的按钮
该按钮可以查看和编辑组件的 JSON 配置
默认值:
false类型:
boolean示例:
<template>
<m-editor :disabled-show-src="true"></m-editor>
</template>disabledDataSource
详情:
禁用数据源功能
禁用后,左侧面板将不显示数据源选项卡
默认值:
false类型:
boolean示例:
<template>
<m-editor :disabled-data-source="true"></m-editor>
</template>disabledCodeBlock
详情:
禁用代码块功能
禁用后,左侧面板将不显示代码块选项卡
默认值:
false类型:
boolean示例:
<template>
<m-editor :disabled-code-block="true"></m-editor>
</template>treeIndent
详情:
组件树、代码块列表、数据源列表的缩进配置(单位:px)
默认值:
undefined类型:
number示例:
<template>
<m-editor :tree-indent="20"></m-editor>
</template>treeNextLevelIndentIncrement
详情:
组件树、代码块列表、数据源列表子节点缩进增量配置(单位:px)
每一级子节点会在父节点缩进基础上增加该值
默认值:
undefined类型:
number示例:
<template>
<!-- 第一级缩进20px,第二级缩进35px,第三级缩进50px -->
<m-editor :tree-indent="20" :tree-next-level-indent-increment="15"></m-editor>
</template>customContentMenu
详情:
用于自定义组件树与画布的右键菜单
该函数会在显示右键菜单前被调用,接收默认菜单项作为参数,返回最终显示的菜单项
默认值:
(menus) => menus类型:
(menus: (MenuButton | MenuComponent)[], data: { node?: MNode; page?: MPage; parent?: MContainer; stage?: StageCore }) => (MenuButton | MenuComponent)[]示例:
<template>
<m-editor :custom-content-menu="customContentMenu"></m-editor>
</template>
<script setup>
const customContentMenu = (menus, { node }) => {
// 为特定类型的组件添加自定义菜单
if (node?.type === 'container') {
menus.push({
type: 'button',
text: '清空容器',
handler: () => {
// 清空容器的逻辑
},
});
}
// 可以过滤掉某些菜单项
return menus.filter(menu => menu.text !== '删除');
};
</script>layerNodeIsExpandable
详情:
用于自定义判断"已选组件"面板中组件树节点是否可展开(即是否要展示为拥有子节点的形态)
该函数返回
true时,节点会显示展开图标,并在展开后渲染子节点容器;返回false时,展开图标显示为透明占位,且不渲染子节点容器默认行为:当节点的
items中至少存在一个visible状态为true的子节点时认为可展开(被搜索过滤隐藏的子节点不会让父节点显示为可展开)默认值:
defaultIsExpandable类型:
(data: TreeNodeData, nodeStatusMap: Map<Id, LayerNodeStatus>) => boolean示例:
<template>
<m-editor :layer-node-is-expandable="layerNodeIsExpandable"></m-editor>
</template>
<script setup>
import { defaultIsExpandable } from '@tmagic/editor';
// 即使没有可见子节点,特定类型的容器节点也保持展开图标可见
const layerNodeIsExpandable = (data, nodeStatusMap) => {
if (data.type === 'my-special-container') {
return true;
}
return defaultIsExpandable(data, nodeStatusMap);
};
</script>TIP
该函数仅作用于"已选组件"面板的组件树节点,不影响代码块、数据源等其它面板内的树。
第三方业务可从 @tmagic/editor 直接导入 defaultIsExpandable 复用默认逻辑作为兜底。
beforeLayerNodeDblclick
详情:
"已选组件"面板组件树节点双击前的钩子函数
在用户双击组件树节点时,先于默认行为执行;返回
false时阻止默认行为(默认行为是切换可展开节点的展开/收起状态)。返回其他值(包括true、undefined、Promise)则继续执行默认行为,并向上抛出layer-node-dblclick事件。常见用途:拦截特定类型节点的双击行为,或在双击时执行业务自定义动作(如重命名、打开抽屉等)后阻断默认展开/收起。
默认值:
undefined类型:
(event: MouseEvent, data: TreeNodeData) => boolean | void | Promise<boolean | void>示例:
<template>
<m-editor
:before-layer-node-dblclick="beforeLayerNodeDblclick"
@layer-node-dblclick="onLayerNodeDblclick"
></m-editor>
</template>
<script setup>
// 双击 page 节点时阻止默认的展开/收起行为
const beforeLayerNodeDblclick = (event, data) => {
if (data.type === 'page') {
return false;
}
};
const onLayerNodeDblclick = (event, data) => {
console.log('双击节点', data.id);
};
</script>TIP
- 该钩子仅作用于"已选组件"面板的组件树节点,不影响画布上的双击行为(画布双击请使用
beforeDblclick)。 - 返回
false时,会同时阻断默认的"展开/收起"行为以及向上抛出的layer-node-dblclick事件;返回其他值则继续触发默认行为并抛出事件。
extendFormState
详情:
扩展表单状态
用于在属性表单中注入自定义的状态数据,这些数据可以在表单配置的各个字段为函数时的第一个参数中获取
默认值:
undefined类型:
(state: FormState) => Record<string, any> | Promise<Record<string, any>>示例:
<template>
<m-editor :extend-form-state="extendFormState"></m-editor>
</template>
<script setup>
const extendFormState = async (state) => {
// 返回自定义的状态数据
return {
// 可以是同步数据
currentUser: {
name: 'Admin',
role: 'admin',
},
// 也可以是异步获取的数据
projectConfig: await fetchProjectConfig(),
};
};
</script>TIP
扩展的状态可以在表单配置中通过 state 访问,例如:
{
name: 'title',
text: '标题',
// 根据扩展的状态动态设置
disabled: (state) => state.currentUser.role !== 'admin',
}historyListExtraTabs
详情:
历史记录面板 的自定义扩展 tab。
业务方可借此在历史记录面板内置的「页面 / 数据源 / 代码块」三个 tab 之后追加自定义模块的历史 tab,例如某个自定义模块维护自己的操作历史时,可在面板中增加一个独立的 tab 来展示与回滚。
默认值:
[]类型:
HistoryListExtraTab[]查看 HistoryListExtraTab 类型定义
ts/** * 历史记录面板(HistoryListPanel)的自定义扩展 tab。 * * 业务方可通过 Editor 的 `historyListExtraTabs` 注入额外的历史记录 tab, * 例如某个自定义模块维护自己的操作历史时,可以在历史记录面板中增加一个 * 独立的 tab 来展示与回滚。内置的「页面 / 数据源 / 代码块」三个 tab 之后 * 会依次追加这些扩展 tab。 */ export interface HistoryListExtraTab { /** tab 唯一标识,作为 TMagicTabs 的 name */ name: string; /** tab 显示文案,支持传入函数以展示动态内容(如记录数量) */ label: string | (() => string); /** tab 内容区渲染的组件(Vue 组件或字符串标签) */ component: any; /** 传入内容组件的 props */ props?: Record<string, any>; /** 内容组件的事件监听 */ listeners?: Record<string, (..._args: any[]) => any>; }示例:
<template>
<m-editor :menu="menu" :history-list-extra-tabs="historyListExtraTabs"></m-editor>
</template>
<script setup>
import { markRaw } from 'vue';
import MyModuleHistoryTab from './MyModuleHistoryTab.vue';
const historyListExtraTabs = [
{
name: 'my-module',
// label 支持字符串或函数,函数形式便于展示动态数量
label: () => '我的模块',
component: markRaw(MyModuleHistoryTab),
// 传入内容组件的 props
props: { foo: 'bar' },
// 内容组件的事件监听
listeners: {
goto: (cursor) => console.log(cursor),
},
},
];
</script>TIP
内容组件内部可自行通过 useServices() 获取 historyService 等服务来读取与回滚自定义模块的历史。
pageBarSortOptions
详情:
页面标签栏的拖拽排序配置参数
用于配置页面标签的拖拽排序行为
默认值:
undefined类型:
PageBarSortOptions查看 PageBarSortOptions 类型定义
tsexport type PartSortableOptions = Omit<Options, 'onStart' | 'onUpdate'>; export interface PageBarSortOptions extends PartSortableOptions { /** 在onUpdate之后调用 */ afterUpdate?: (event: SortableEvent, sortable: Sortable) => void | Promise<void>; /** 在onStart之前调用 */ beforeStart?: (event: SortableEvent, sortable: Sortable) => void | Promise<void>; }示例:
<template>
<m-editor :page-bar-sort-options="sortOptions"></m-editor>
</template>
<script setup>
const sortOptions = {
// 是否启用拖拽排序
animation: 150,
// 拖拽手柄的class
handle: '.page-bar-item',
// 其他 sortablejs 配置
};
</script>pageFilterFunction
详情:
页面搜索/过滤函数
用于自定义页面的搜索逻辑,在页面列表中输入关键词时会调用该函数进行过滤
默认值:
undefined类型:
(page: MPage | MPageFragment, keyword: string) => boolean示例:
<template>
<m-editor :page-filter-function="pageFilterFunction"></m-editor>
</template>
<script setup>
const pageFilterFunction = (page, keyword) => {
// 自定义搜索逻辑
// 不仅搜索页面名称,还搜索页面的其他属性
return (
page.name?.includes(keyword) ||
page.title?.includes(keyword) ||
page.id?.includes(keyword)
);
};
</script>