用途
本技能用于指导为 Univer(电子表格/文档/演示引擎)开发自定义插件,扩展 Univer 的功能。适用于编写插件、注册命令/变更/操作、扩展 Facade 等场景。
兼容性
本技能针对 Univer v0.21.x 编写。核心插件模式(生命周期、依赖注入、命令)保持稳定,但具体服务令牌和 Facade 类可能变化。当用户现有代码库模式与示例不同时,优先采用用户代码库的模式。
快速开始
脚手架生成新插件
使用捆绑脚本生成最小插件骨架:
# 如果安装到 ~/.codex/skills/
npx tsx ~/.codex/skills/univer-plugin-dev/scripts/scaffold-plugin.ts my-plugin --path ./src/plugins
# 或直接从本仓库运行
npx tsx ~/univer-sdk-skills/skills/univer-plugin-dev/scripts/scaffold-plugin.ts my-plugin --path ./src/plugins
生成结构:
my-plugin/
├── src/
│ ├── index.ts
│ ├── plugin.ts
│ ├── commands/
│ │ └── commands.my-command.ts
│ ├── controllers/
│ │ └── my-menu.controller.ts
│ └── facade/
│ └── f-univer.ts
├── package.json
└── tsconfig.json
在应用中注册插件
import { MyPlugin } from './plugins/my-plugin/src';
import './plugins/my-plugin/src/facade/f-univer'; // 用于 Facade 扩展的副作用导入
univer.registerPlugin(MyPlugin);
核心概念
插件生命周期
插件继承自 Plugin 并重写生命周期钩子:
| 钩子 | 时机 | 应做的事 |
|---|---|---|
| onStarting() | 插件挂载,尚无业务单元 | 注册命令、服务、菜单、快捷键 |
| onReady() | 业务单元已创建 | 访问工作簿/文档实例 |
| onRendered() | UI 已渲染 | 依赖 DOM 的初始化 |
| onSteady() | 一切稳定 | 后台任务 |
始终使用 disposeWithMe() 注册可释放资源,以便插件销毁时自动清理。
命令系统
三种命令类型:
- COMMAND — 业务入口。编排变更和操作。若手动推入 IUndoRedoService,则支持撤销/重做。
- MUTATION — 原子数据变更。持久化到快照。自动可撤销。
- OPERATION — UI 状态变更。不持久化。不可撤销。
各类型的完整示例及撤销/重做构造见 references/command-system.md。
依赖注入
Univer 使用自定义 DI 容器(Injector)。服务获取方式:
// 构造函数注入
@Inject(IMenuManagerService) private readonly _menuService: IMenuManagerService
// 访问器注入(在命令处理器中)
const service = accessor.get(IMenuManagerService);
常见服务令牌:
- ICommandService — 注册/执行命令
- IMenuManagerService — 添加菜单/工具栏项
- IShortcutService — 注册键盘快捷键
- IContextMenuService — 上下文菜单
- ComponentManager — 注册 React 组件/图标
- IUniverInstanceService — 获取当前工作簿/文档/幻灯片
- IUndoRedoService — 推入撤销/重做条目
Facade 扩展
扩展 Facade 类以向最终用户暴露插件能力:
import { FWorksheet } from '@univerjs/sheets/facade';
class FWorksheetMyMixin extends FWorksheet {
myMethod(): this {
// 实现
return this;
}
}
FWorksheet.extend(FWorksheetMyMixin);
declare module '@univerjs/sheets/facade' {
interface FWorksheet extends FWorksheetMyMixin {}
}
常见任务
完整示例(子菜单、上下文菜单、Range Popup、组件替换、完整的工具栏+命令+快捷键流水线)见 references/ui-customization.md。
添加工具栏按钮
this._menuManagerService.mergeMenu({
[RibbonOthersGroup.OTHERS]: {
['my-button']: {
order: 10,
menuItemFactory: () => ({
id: 'my-button',
title: 'My Button',
type: MenuItemType.BUTTON,
}),
},
},
});
注册命令
const MyCommand: ICommand = {
id: 'my.command.id',
type: CommandType.COMMAND,
handler: (accessor) => {
// 业务逻辑
return true;
},
};
this._commandService.registerCommand(MyCommand);
扩展 Facade
class FWorksheetMyMixin extends FWorksheet {
myMethod(): this { return this; }
}
FWorksheet.extend(FWorksheetMyMixin);
declare module '@univerjs/sheets/facade' {
interface FWorksheet extends FWorksheetMyMixin {}
}
参考资料
- 插件架构:references/plugin-architecture.md — 生命周期、DI、服务注册、控制器模式
- 命令系统:references/command-system.md — COMMAND / MUTATION / OPERATION、撤销/重做、变更工厂、自定义变更
- Facade 扩展:references/facade-extension.md — 扩展 FUniver、FWorkbook、FWorksheet、FRange,多扩展合并策略
- UI 定制:references/ui-customization.md — 菜单、子菜单、快捷键、上下文菜单、弹窗、组件替换
- 事件系统:references/event-system.md — 事件、钩子、自定义事件、RxJS 流
另见 univer-integrate 技能:
- 自定义公式函数(univer-integrate 技能)
- 权限(univer-integrate 技能)
- 网络层(univer-integrate 技能)
脚本
- 脚手架:scripts/scaffold-plugin.ts — 生成新插件骨架