- 前端
- 音视频
【免费下载链接】open-file-viewer
A framework-agnostic embedded file viewer for vanilla JavaScript, React, Vue and Svelte. Put PDF, Office, images, media, archives, email, drawings, 3D, GIS and engineering files inside one stable container.
Open File Viewer 是一个跨框架的文件预览 SDK,把 PDF、Office、图片、音视频、压缩包、邮件、图纸、3D、GIS 等格式放进同一个可控容器,同时支持原生 JS、React、Vue 和 Svelte。它的核心设计是插件化:每种文件格式由一个独立插件负责,而插件要遵守的协议——PreviewPlugin——只有 3 个成员。读懂这个协议,你只需要 50 行左右代码,就能让自己的私有格式或业务文件格式也进入统一的预览容器 🧩。
为什么用插件架构:一个容器,N 种格式
大多数业务系统最终都需要附件预览:合同、表格、图纸、压缩包、邮件……如果每种格式都写一套预览逻辑,容器、加载态、错误态、工具栏、多文件队列这些能力就得重复实现。
Open File Viewer 的做法是把这些公共能力全部收敛到 viewer.ts 里的createViewer()容器中,插件只负责回答两个问题:
- 这个文件是不是我的?(
match) - 怎么把它渲染进容器?(
render)
内置插件与格式的对应关系如下:
| 类别 | 插件 | 代表格式 |
|---|---|---|
| 图片 | imagePlugin() | jpg、png、webp、avif、svg、heic |
| 视频 / 音频 | videoPlugin()、audioPlugin() | mp4、webm、mp3、flac |
| 文本 / 代码 | textPlugin() | txt、md、json、js、py、sql |
| PDF / 电子书 | pdfPlugin()、epubPlugin()、xpsPlugin() | pdf、epub、xps |
| Office / OFD | officePlugin()、ofdPlugin() | docx、xlsx、pptx、ofd |
| 工程 / 专业格式 | cadPlugin()、model3dPlugin()、gisPlugin()、drawingPlugin()、xmindPlugin() | dxf、dwg、glb、kml、drawio、xmind |
| 压缩包 / 邮件 | archivePlugin()、emailPlugin() | zip、rar、eml |
| 资产识别 | assetPlugin() | psd、sqlite、wasm、parquet |
完整插件列表见 index.ts 的导出,每个插件都遵循同一套协议,行为因此可以互相替换、裁剪和扩展。
拆解 PreviewPlugin 接口:只有 3 个成员
整个插件协议的定义在 types.ts,短到可以一眼看完:
export interface PreviewPlugin { name: string; match: (file: PreviewFile) => boolean | Promise<boolean>; render: (ctx: PreviewContext) => Promise<PreviewInstance> | PreviewInstance; }逐个理解这三个成员:
name:插件的唯一标识
用于日志与调试。内置插件分别叫"image"、"fallback"等。注意一个特殊约定:名为"fallback"的插件在支持性检测中有终止性含义,自定义插件不要占用这个名字。
match:判断文件是否归你管
入参是一个已经归一化好的PreviewFile对象(定义见 types.ts),包含source、name、extension、mimeType、size等字段。文件归一化逻辑由 detect.ts 的normalizeFile()完成:它会根据扩展名自动补全 MIME 类型,所以插件里可以直接读file.extension和file.mimeType。
一个典型的匹配逻辑可以看 image.ts 的实现——先看 MIME 是否以image/开头,再兜底查扩展名白名单,同时排除dxf这类"名字叫图像但其实不是"的格式。
match允许返回Promise<boolean>,因此你也可以在匹配阶段做异步探测(比如读文件头几个字节判断魔数)。
render:真正干活的渲染函数
render接收一个PreviewContext,返回一个PreviewInstance(可以是同步对象,也可以是 Promise)。前者决定"往哪画",后者决定"容器如何回收你"。
渲染上下文 PreviewContext:容器给了你什么
render收到的ctx对象定义在 types.ts,它把容器侧的所有能力一次性交到你手上:
| 字段 | 作用 |
|---|---|
ctx.host/ctx.viewport | 预览宿主与内容视口(你的渲染目标) |
ctx.file | 当前文件的归一化信息PreviewFile |
ctx.size | 视口当前宽高PreviewSize |
ctx.options | 完整的预览配置(fit、fallback、zoom、messages 等) |
ctx.toolbar | 工具栏上下文,可读取文件、索引、缩放状态 |
ctx.signal | AbortSignal:本次渲染被新请求取代或容器销毁时触发中止 |
ctx.setLoading/ctx.setError | 控制容器的加载态与错误展示 |
容器还会自动帮你做脏活累活:多文件队列切换(next()/previous())、响应式尺寸监听、工具栏按钮的启用/禁用、主题与国际化文案、打印前的preparePrint流程——这些全部发生在 viewer.ts 的renderFile()里,插件完全不需要关心。
返回值 PreviewInstance:一份生命周期契约
render必须返回一个PreviewInstance对象(定义见 types.ts),它只有 1 个必填成员 + 4 个可选能力:
export interface PreviewInstance { resize?: (size: PreviewSize) => void; // 容器尺寸变化时响应 goToPage?: (page: number) => boolean; // 分页预览跳转(1 基) command?: (command: PreviewCommand) => void | boolean; // 响应缩放/旋转指令 canCommand?: (command: PreviewCommand) => boolean; // 声明哪些指令可用 preparePrint?: () => void | Promise<void>; // 打印前准备好懒加载内容 destroy: () => void; // 必填:清理一切副作用 }resize(size):窗口或布局变化时容器会调用它,Canvas/WebGL 类插件必须实现。command/canCommand:容器内置了滚轮、捏合手势缩放(见 viewer.ts 的手势安装逻辑),如果你的预览支持zoom-in、rotate-right等指令,实现这两个方法后工具栏和手势会自动联动。destroy():这是硬性约定。切文件、销毁容器时容器都会调用它,你要在这里移除 DOM、断开事件监听、撤销 object URL、停止 Worker、释放 Canvas/WebGL 资源。
插件匹配机制:顺序、兜底与预检查
容器如何从一堆插件里选出渲染者?逻辑在 viewer.ts 的findPlugin(),非常直白:按你传入数组的顺序依次调用match(),第一个返回true的插件胜出。
两个关键细节:
fallbackPlugin()自动垫底。渲染时容器会自动在你的插件列表末尾追加 fallback 插件,它的match()永远返回true。未命中任何原生插件的文件会走到这里,展示"格式不支持 + 下载"面板(或你通过renderFallback提供的自定义渲染),保证任何文件都不会白屏。- 顺序即优先级。
csv同时能被textPlugin()和officePlugin()命中——想让表格走电子表格样式,就把officePlugin()放在前面。
如果你在挂载预览器之前就想判断"这个文件能不能预览",可以用 support.ts 导出的isPreviewSupported()。它复用同一套match()顺序做纯检查,不挂载任何 DOM、不调用render(),且fallbackPlugin()命中不算"原生支持"——非常适合做"可在线预览 / 请下载"这类 UI 分流。
实战:50 行代码接入一个新格式
假设业务里有一种.ticket格式的工单文件,想在预览容器里展示。参照 README.md 中的 Plugin Development 章节,完整实现如下:
import type { PreviewPlugin } from "@open-file-viewer/core"; export function ticketPlugin(): PreviewPlugin { return { name: "ticket", match(file) { return file.extension === "ticket"; }, async render(ctx) { const panel = document.createElement("div"); panel.className = "ticket-preview"; panel.textContent = `工单:${ctx.file.name}`; ctx.viewport.append(panel); return { resize(size) { // 视口尺寸变化时重排,例如缩放画布 }, destroy() { panel.remove(); } }; } }; }然后在创建预览器时把它插进插件列表的合适位置(fallbackPlugin()永远放最后):
const viewer = createViewer({ container: "#viewer", file: ticketFile, fileName: "TK-2026-001.ticket", width: "100%", height: "70vh", toolbar: true, plugins: [imagePlugin(), textPlugin(), ticketPlugin(), pdfPlugin({ workerSrc }), fallbackPlugin()] });就这么简单:match圈定管辖范围,render画进ctx.viewport,返回的对象负责自清理——整个流程不超过 50 行。React / Vue / Svelte 侧只需把同一个插件数组传给各自适配器组件(如<FileViewer plugins={plugins} />),四端行为完全一致,示例见 examples/ 下的 vanilla、react、vue、svelte 四个工程。
如果格式更复杂(比如私有二进制),协议同样够用:在render里fetch你后端的转换接口、拿回 SVG/PNG 或 PDF 再渲染即可;容器已经替你处理了加载中、错误、多文件切换与资源销毁的时机。
插件开发清单:5 条铁律
来自 README.md 的 Plugin constraints,也是核心源码实际执行的约定:
- ✅只往
ctx.viewport里渲染,不要动ctx.host或外部 DOM - ✅默认不打开新窗口,一切展示留在容器内
- ✅需要响应尺寸变化就实现
resize(size) - ✅实现
destroy():清理事件、object URL、定时器、Canvas/WebGL 等所有副作用 - ✅尊重
ctx.signal:切换文件时本次渲染会被中止,长任务应在关键节点检查signal.aborted
相关源码速查
| 文件 | 说明 |
|---|---|
| types.ts | PreviewContext、PreviewInstance、PreviewPlugin三大接口定义 |
| viewer.ts | renderFile():加载态、插件选择、实例挂载与错误处理 |
| viewer.ts | findPlugin():按顺序match(),fallback 垫底 |
| detect.ts | normalizeFile():扩展名 → MIME 归一化 |
| support.ts | isPreviewSupported():挂载前预判支持性 |
| fallback.ts | 兜底插件:不支持格式的下载面板 |
| lite.ts | 轻量入口:仅含运行时 + 图片 + PDF + fallback |
| plugins/ | 全部内置格式插件实现,是最好的活教材 |
想深入时,建议直接打开 image.ts 或 cad.ts 这类内置插件对照协议读一遍——它们分别代表了"最简单"和"最复杂"两端的插件写法。协议本身保持如此精简,正是 Open File Viewer 能让任何新格式以最小成本融入统一预览容器的原因。
- 前端
- 音视频
【免费下载链接】open-file-viewer
A framework-agnostic embedded file viewer for vanilla JavaScript, React, Vue and Svelte. Put PDF, Office, images, media, archives, email, drawings, 3D, GIS and engineering files inside one stable container.
相关推荐
DLSS Swapper 完全指南:5 分钟完成游戏 DLSS 版本替换、回退与效果验证
DLSS Swapper 完全指南:5 分钟完成游戏 DLSS 版本替换、回退与效果验证 DLSS Swapper 是一款开源的图形加速库管理工具,可以下载并管
桌面应用Smart-Admin文件预览:file-preview组件与格式支持全解析
Smart Admin文件预览:file preview组件与格式支持全解析 引言:你还在为文件预览功能头疼吗? 企业级应用开发中,文件预览功能往往面临格式繁杂
后端前端低代码认证鉴权移动开发PP-OCRv6_tiny_rec数据预处理与后处理:CTCLabelDecode技术深度解析
PP OCRv6_tiny_rec数据预处理与后处理:CTCLabelDecode技术深度解析 PP OCRv6_tiny_rec_safetensors是飞桨
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考