多实例示例

← 单实例示例 | 核心 API →

多实例演示使用独立 Subframe:父页面负责 Tab 和工具栏,每个 Tab 的 OnlyOffice Embed SDK 运行时都放在一个独立子域名页面中。

onlyoffice.localhost
├── rat.onlyoffice.localhost/subframe      (🐀 鼠)
├── ox.onlyoffice.localhost/subframe       (🐂 牛)
├── tiger.onlyoffice.localhost/subframe    (🐅 虎)
├── rabbit.onlyoffice.localhost/subframe   (🐇 兔)
├── dragon.onlyoffice.localhost/subframe   (🐉 龙)
├── snake.onlyoffice.localhost/subframe    (🐍 蛇)
├── horse.onlyoffice.localhost/subframe    (🐎 马)
├── goat.onlyoffice.localhost/subframe     (🐐 羊)
├── monkey.onlyoffice.localhost/subframe   (🐒 猴)
├── rooster.onlyoffice.localhost/subframe  (🐓 鸡)
├── dog.onlyoffice.localhost/subframe      (🐕 狗)
└── pig.onlyoffice.localhost/subframe      (🐖 猪)

生产环境将上述主机名替换为 rat.onlyoffice.agent-bridges.com 等固定 12 个槽位。每个子框架的响应都带有 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 编辑器。

示例

切换标签页,实例状态会保留

更多
加载中...

设计要点

要点说明
固定槽位按鼠、牛、虎、兔、龙、蛇、马、羊、猴、鸡、狗、猪顺序分配 12 个固定槽位,关闭后可复用
独立 origin第一个 Tab 使用 rat.onlyoffice.localhost,后续 Tab 依次使用 ox.onlyoffice.localhosttiger.onlyoffice.localhost
Tab 标识每个 Tab 显示对应的生肖 emoji,便于在多个编辑器之间快速区分
独立运行时每个 /subframe 页面拥有自己的 OnlyOfficeManager、SDK 和事件总线
懒加载Tab 首次激活时,父页通过 RPC 发送 open 请求
状态保留非激活 Tab 只隐藏外层 iframe,不卸载子框架
跨窗口控制上传、主题、只读、导出、批注、修订和 Connector 都通过 RPC 转发
关闭 Tab父页发送 destroy,再移除对应 iframe
资源切换更新 iframe 的资源参数并重新加载各子框架
响应头TanStack Start 的 Cloudflare Worker 全局响应头设置 Origin-Agent-Cluster: ?1

Tab 数据模型

type TabItem = {
  id: string;
  label: string;
  containerId: string;
  subframeHost: string;
  chineseZodiac: { id: string; name: string; emoji: string };
  fileName: string;
  readOnly: boolean;
  docKind: "word" | "excel" | "ppt";
};

子框架 URL

const url = new URL("/subframe", getSubframeOrigin(tab.subframeHost));
url.searchParams.set("instance", tab.id);
url.searchParams.set("resourceMode", resourceState.mode);

getSubframeOrigin("rat") 在本地开发时返回 http://rat.onlyoffice.localhost:<port>;生产环境返回 https://rat.onlyoffice.agent-bridges.com。12 个固定主机名都指向同一个 Cloudflare Worker,但每个主机名仍然是独立 origin。

RPC 生命周期

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 命令则只传递函数源码字符串和调用结果。