#插件开发指南
Tangramino 提供了强大的插件系统,允许开发者通过插件机制扩展编辑器的功能。插件可以介入编辑器的生命周期、修改 Schema、转换物料、拦截操作等。
完整的插件 API 参考请查看 插件系统 API
#快速入门
#使用 definePlugin 创建插件
推荐使用 definePlugin 工厂函数创建类型安全的插件:
import { definePlugin } from '@tangramino/base-editor';
const myPlugin = definePlugin(() => ({
id: 'my-plugin',
onInit(ctx) {
console.log('插件初始化');
// 返回清理函数(可选)
return () => console.log('插件清理');
},
onDispose(ctx) {
console.log('插件销毁');
},
}));#带配置的插件
interface MyPluginOptions {
debug?: boolean;
maxItems?: number;
}
const configPlugin = definePlugin<EditorPlugin, MyPluginOptions>((options) => ({
id: 'config-plugin',
onInit(ctx) {
if (options.debug) {
console.log('Debug mode enabled');
}
},
}));
// 使用
const plugins = [configPlugin({ debug: true, maxItems: 10 })];#插件接口
插件是一个符合 EditorPlugin 接口的对象:
interface EditorPlugin {
// 元数据
id: string; // 唯一标识
dependencies?: string[]; // 依赖的插件
priority?: number; // 优先级(越小越先执行)
// 生命周期
onInit?: (ctx: PluginContext) => (() => void) | void;
onDispose?: (ctx: PluginContext) => void;
// 物料转换
transformMaterials?: (materials: Material[]) => Material[];
// Schema 操作钩子
onBeforeInsert?: (schema, targetId, element) => boolean | void;
onAfterInsert?: (schema, insertedId) => void;
onBeforeMove?: (schema, sourceId, targetId) => boolean | void;
onAfterMove?: (schema, movedId) => void;
onBeforeRemove?: (schema, targetId) => boolean | void;
onAfterRemove?: (schema, removedId) => void;
onBeforeUpdateProps?: (schema, targetId, props) => boolean | void;
onAfterUpdateProps?: (schema, targetId) => void;
// 编辑器钩子
onElementActivate?: (element, parentChain) => void;
onElementDeactivate?: (element) => void;
onCanvasUpdated?: (ctx) => void;
}#插件上下文
插件通过 PluginContext 访问编辑器能力:
interface PluginContext {
engine: Engine; // 引擎实例
getSchema: () => Schema; // 获取当前 Schema
setSchema: (schema: Schema) => void; // 更新 Schema
getMaterials: () => Material[]; // 获取物料列表
getPlugin: <T>(id: string) => T | undefined; // 获取其他插件
}#实战示例
#示例 1:表单插件
为表单内的组件自动包裹 Form.Item:
import { definePlugin, useEditorCore } from '@tangramino/base-editor';
import { SchemaUtils } from '@tangramino/engine';
import { Form } from 'antd';
const FormItem = Form.Item;
// 高阶组件:自动包裹 Form.Item
const withForm = (Component: React.ComponentType<any>) => {
return (props: any) => {
const { label, name, required, tooltip } = props;
const elementId = props['data-element-id'];
const { schema } = useEditorCore();
const isInForm = useMemo(() => {
const parents = SchemaUtils.getParents(schema, elementId);
const parentId = parents[0];
return schema.elements[parentId]?.type === 'form';
}, [schema, elementId]);
if (isInForm) {
return (
<FormItem label={label} name={name} required={required} tooltip={tooltip}>
<Component {...props} />
</FormItem>
);
}
return <Component {...props} />;
};
};
export const formPlugin = definePlugin(() => ({
id: 'form',
transformMaterials(materials) {
return materials.map(material => ({
...material,
Component: withForm(material.Component),
}));
},
onElementActivate(element, parentElements) {
// 当元素在表单中时,动态添加表单项配置
const isInForm = parentElements.some(p => p.type === 'form');
if (isInForm) {
// 动态注入表单配置面板...
}
},
}));#示例 2:物料增强插件
为所有物料自动添加通用属性:
import { definePlugin } from '@tangramino/base-editor';
export const materialPlugin = definePlugin(() => ({
id: 'material',
transformMaterials(materials) {
return materials.map((material) => {
// 注入默认方法
const methods = material.contextConfig?.methods || [];
methods.unshift({ name: 'init', description: '初始化' });
// 注入通用属性配置
const panels = material.editorConfig?.panels || [];
const attrPanel = panels.find((p) => p.title === '属性');
if (attrPanel?.configs) {
attrPanel.configs.unshift({
label: '别名',
field: 'alias',
required: true,
uiType: 'input',
});
}
return {
...material,
contextConfig: { ...material.contextConfig, methods },
};
});
},
}));#示例 3:验证插件
拦截操作并进行验证:
export const validationPlugin = definePlugin(() => ({
id: 'validation',
onBeforeRemove(schema, targetId) {
// 禁止删除根元素
if (targetId === schema.layout.root) {
console.warn('不能删除根元素');
return false;
}
return true;
},
onBeforeInsert(schema, targetId, element) {
// 限制嵌套层级
const parents = SchemaUtils.getParents(schema, targetId);
if (parents.length >= 10) {
console.warn('嵌套层级不能超过 10 层');
return false;
}
return true;
},
}));#内置插件
#historyPlugin - 历史记录
提供撤销/重做功能:
import { historyPlugin, type HistoryPlugin } from '@tangramino/base-editor';
const plugins = [historyPlugin({ limit: 50 })];
// 在组件中使用
const history = ctx.getPlugin<HistoryPlugin>('history');
history?.undo();
history?.redo();#modePlugin - 模式切换
设置编辑/渲染模式:
import { modePlugin } from '@tangramino/base-editor';
const plugins = [modePlugin('edit')]; // 或 'render'#使用插件
在 EditorProvider 中注册:
import { EditorProvider } from '@tangramino/base-editor';
import {
formPlugin,
materialPlugin,
validationPlugin,
historyPlugin,
} from './plugins';
const Editor = () => (
<EditorProvider
materials={materials}
schema={schema}
plugins={[
historyPlugin(),
formPlugin(),
materialPlugin(),
validationPlugin(),
]}
>
{/* 编辑器内容 */}
</EditorProvider>
);