← 单实例示例 | 核心 API →
多实例演示使用独立 Subframe:父页面负责 Tab 和工具栏,每个 Tab 的 OnlyOffice 运行时都放在一个独立子域名页面中。
a.localhost
├── a.b.localhost/subframe (Word)
├── b.b.localhost/subframe (Excel)
└── c.b.localhost/subframe (PPT)
每个子框架的响应都带有 Origin-Agent-Cluster: ?1。因此 SDK 的全局对象、事件总线、socket mock 和文档状态不会在多实例之间共享;父页只通过带 source、实例 ID 和精确目标 origin 校验的 postMessage RPC 控制子框架。
在线演示:站点路由 /docs/demos/multi
父页面源码:src/features/demo/tabs-multi-page.tsx
子框架页面:src/features/demo/onlyoffice-subframe-page.tsx
消息协议:src/features/demo/subframe-protocol.ts
下方为可交互的多实例 Tab 编辑器。
| 要点 | 说明 |
|---|
| 独立 origin | 第一个 Tab 使用 a.b.localhost,后续 Tab 依次使用 b.b.localhost、c.b.localhost |
| 独立运行时 | 每个 /subframe 页面拥有自己的 OnlyOfficeManager、SDK 和事件总线 |
| 懒加载 | Tab 首次激活时,父页通过 RPC 发送 open 请求 |
| 状态保留 | 非激活 Tab 只隐藏外层 iframe,不卸载子框架 |
| 跨窗口控制 | 上传、主题、只读、导出、批注、修订和 Connector 都通过 RPC 转发 |
| 关闭 Tab | 父页发送 destroy,再移除对应 iframe |
| 资源切换 | 更新 iframe 的资源参数并重新加载各子框架 |
| 响应头 | TanStack Start 的 Cloudflare Worker 全局响应头设置 Origin-Agent-Cluster: ?1 |
type TabItem = {
id: string;
label: string;
containerId: string;
subframeHost: string;
fileName: string;
readOnly: boolean;
docKind: "word" | "excel" | "ppt";
};
const url = new URL("/subframe", getSubframeOrigin(tab.subframeHost));
url.searchParams.set("instance", tab.id);
url.searchParams.set("resourceMode", resourceState.mode);
getSubframeOrigin("a") 在本地开发时返回 http://a.b.localhost:<port>;生产环境会根据当前站点域名生成对应的 a.b.<domain> 子域名。部署时需要让这些子域名解析到同一个应用服务。
iframe load → subframe:ready
parent → request/open
subframe → event/loading-change + event/document-ready
subframe → response/open
parent → request/set-theme | request/set-read-only | request/editor
子框架不会把 SDK 原始对象传回父页:批注和修订会先转换为可结构化克隆的数据,Connector 命令则只传递函数源码字符串和调用结果。