单实例示例
单实例场景使用独立 Subframe:父页面保留工具栏和状态,OnlyOffice Embed SDK 运行在固定的 rat.onlyoffice.* 子域名中。这样即使只有一个编辑器,也不会把 SDK 全局对象、事件总线和文档状态放进宿主页面。
在线演示:站点路由 /docs/demos/single
完整源码:src/features/demo/office-preview-page.tsx
在线演示
下方为可交互的单实例编辑器。
单实例场景使用独立 Subframe:父页面保留工具栏和状态,OnlyOffice Embed SDK 运行在固定的 rat.onlyoffice.* 子域名中。这样即使只有一个编辑器,也不会把 SDK 全局对象、事件总线和文档状态放进宿主页面。
在线演示:站点路由 /docs/demos/single
完整源码:src/features/demo/office-preview-page.tsx
下方为可交互的单实例编辑器。
rat.onlyoffice.localhost(生产环境为 rat.onlyoffice.agent-bridges.com)的 /subframe iframeSubframeManager 通过精确 targetOrigin 和 postMessage RPC 请求子框架打开文档openDocument / downloadExport / setReadOnly / setTheme / toggleLanguage / printLogsdestroy,再释放父页面管理器"use client";
import { memo } from "react";
const OnlyOfficeSubframeHost = memo(function OnlyOfficeSubframeHost({
src,
onLoad,
}: {
src: string;
onLoad: () => void;
}) {
return (
<iframe
src={src}
title="OnlyOffice Embed SDK · 🐀 鼠"
data-onlyoffice-subframe="true"
className="absolute inset-0 h-full w-full border-0"
onLoad={onLoad}
/>
);
});
useEffect(() => {
const manager = new SubframeManager({
containerId: "onlyoffice-subframe-editor",
fileType: FILE_TYPE.DOCX,
defaultFileName: "New_Document.docx",
readOnly,
theme: currentTheme,
instanceId: "single-editor",
targetOrigin: getSubframeOrigin("rat"),
frame: frameRef.current,
});
managerRef.current = manager;
void manager.openDocument({
fileName: "New_Document.docx",
isNew: true,
});
return () => {
manager.destroy();
managerRef.current = null;
};
}, []);
const handleOpenDocument = (fileName: string, file?: File) =>
managerRef.current?.openDocument({ fileName, file, readOnly });
const handleExport = () => managerRef.current?.downloadExport();
const handleToggleReadOnly = async () => {
const manager = managerRef.current;
await manager?.setReadOnly(!manager.getReadOnly());
setReadOnly(managerRef.current?.getReadOnly() ?? false);
};
const handleThemeChange = async (theme: OfficeTheme) => {
await managerRef.current?.setTheme(theme);
setCurrentThemeState(managerRef.current?.getTheme() ?? theme);
};
const handleLanguageSwitch = async () => {
const nextLang = await managerRef.current?.toggleLanguage();
setCurrentLangState(nextLang);
};
export function OfficePreviewPage({ embedded = false, ...props }) {
return (
<div className={`flex flex-col bg-white ${embedded ? "h-full min-h-0" : "h-screen"}`}>
<header>{/* 语言 / 主题 / 上传 / 新建 / 导出 / 只读 */}</header>
<div className="relative min-h-0 flex-1">
<OnlyOfficeSubframeHost src={subframeSrc} onLoad={handleFrameLoad} />
{loading && <LoadingOverlay />}
</div>
<input ref={fileInputRef} type="file" className="hidden" onChange={...} />
</div>
);
}
| 能力 | API |
|---|---|
| 上传文件 | manager.openDocument({ fileName, file }) |
| 新建空白 | manager.openDocument({ fileName: defaultFileName }) |
| 导出 | manager.downloadExport() |
| 只读切换 | manager.setReadOnly(!manager.getReadOnly()) |
| 主题 | manager.setTheme(theme) |
| 语言 | manager.toggleLanguage() |
| 打印日志 | manager.printLogs() |