# docvu **Repository Path**: Lin_su/docvu ## Basic Information - **Project Name**: docvu - **Description**: No description available - **Primary Language**: Unknown - **License**: MIT - **Default Branch**: main - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-09-10 - **Last Updated**: 2026-09-10 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # DocVu SDK > 跨框架文档预览 SDK —— 一行代码在 Web 应用中嵌入 PDF、Excel、图片、视频、音频、Markdown、代码等多种格式的预览能力。[在线演示](https://zxdz.asia/html/docvu/index.html) [![npm](https://img.shields.io/npm/v/@docvu/docvu)](https://www.npmjs.com/package/@docvu/docvu) [![downloads](https://img.shields.io/npm/dm/@docvu/docvu)](https://www.npmjs.com/package/@docvu/docvu) [![license](https://img.shields.io/npm/l/@docvu/docvu)](https://www.npmjs.com/package/@docvu/docvu) [![node](https://img.shields.io/node/v/@docvu/docvu)](https://www.npmjs.com/package/@docvu/docvu) [![docvu logo](./logo.jpg)](https://zxdz.asia/html/docvu/index.html) ## 特性 - 🚀 **一行集成** — 引入 JS + 一个 CSS 文件即可运行功能完整的预览器 - 📄 **多格式支持** — PDF、XLSX/XLS/CSV、图片、视频、音频、Markdown、纯文本、代码等 8 大类、95+ 扩展名 - 🎨 **明暗主题** — 内置浅色 / 深色主题,支持运行时切换(PDF 模式下走 EmbedPDF 原生 `setTheme`,无需重建) - 🔧 **完整 API** — 缩放、旋转、翻页、全屏、下载、主题切换、事件订阅 - 📱 **响应式布局** — 容器自适应,支持触摸操作 - 🔌 **跨框架兼容** — 原生 JS 实现,可嵌入 Vue3 / React / 原生 HTML - 📦 **零运行时依赖打包** — ExcelJS / SheetJS / EmbedPDF Snippet 均通过动态 `import()` 按需加载,不进产物主包 - 🌐 **本地优先 + CDN 兜底** — 严格内网环境可一键关闭 CDN 回退(`allowCdn: false`) - 🇨🇳 **中文优先** — 工具栏、PDF 内嵌 UI、错误提示默认中文 - ⚡ **大文件优化** — Excel 虚拟滚动(万行级不卡顿)+ 自适应缓冲;PDF 走 PDFium WASM 原生渲染 ## 安装 ```bash npm install @docvu/docvu # 或 yarn add @docvu/docvu # 或 pnpm add @docvu/docvu ``` > **渲染引擎依赖**:PDF / Word / Excel / PPT / OFD / CAD / 代码高亮的第三方解析库均已声明为 `optionalDependencies`,执行 `npm install @docvu/docvu` 时自动安装,所有格式开箱即用。 > > 若需纯 CDN 部署(最小化 node_modules),可加 `--no-optional` 跳过安装:`npm install @docvu/docvu --no-optional`,SDK 会在首次预览对应格式时从公共 CDN 动态加载(可用 `allowCdn: false` 关闭 CDN 回退)。 > > 框架适配 `@docvu/docvu/vue`、`@docvu/docvu/react` 为独立子入口,`vue` / `react` 为可选 peerDependencies,按需安装即可。 ## 快速开始 ### Vue 3 **推荐:使用 `` 组件**(自动管理生命周期、响应式 props、暴露 viewer 实例) ```vue ``` **备选:手动 `createViewer`**(需要自行管理 mount / destroy) ```vue ``` ### React **推荐:使用 `` 组件**(自动管理生命周期、useImperativeHandle 暴露方法) ```tsx import { useRef } from 'react' import { DocVu } from '@docvu/docvu/react' import type { DocVuHandle } from '@docvu/docvu/react' import '@docvu/docvu/style.css' function DocumentViewer() { const docVuRef = useRef(null) // 可选:通过 ref 调用底层 viewer 方法 const zoomIn = () => docVuRef.current?.zoom(1.2) return ( console.log('Viewer ready')} onLoad={() => console.log('File loaded')} onError={(err) => console.error('Error:', err)} /> ) } ``` **备选:手动 `createViewer`** ```tsx import { useEffect, useRef } from 'react' import { createViewer } from '@docvu/docvu' import '@docvu/docvu/style.css' function DocumentViewer() { const containerRef = useRef(null) const viewerRef = useRef | null>(null) useEffect(() => { if (!containerRef.current) return viewerRef.current = createViewer({ target: containerRef.current, file: 'https://example.com/document.pdf', theme: 'light', toolbar: true }) viewerRef.current.mount() return () => viewerRef.current?.destroy() }, []) return
} ``` > **框架适配说明**:`@docvu/docvu/vue` 和 `@docvu/docvu/react` 为独立子入口,`vue` / `react` 为 **可选 peerDependencies**。仅使用对应框架时才需安装,核心 `@docvu/docvu` 包不依赖任何前端框架。 ### 原生 HTML(UMD / IIFE) ```html
``` ## 样式引入策略 SDK 提供两种样式引入方式,按需选择: | 方式 | 写法 | 说明 | |------|------|------| | **全量引入** | `import '@docvu/docvu/style.css'` | 一次性包含 Viewer + 全部渲染器样式(推荐快速接入) | | **按需引入** | `import '@docvu/docvu/viewer.css'` | 仅引入 Viewer 容器 / 工具栏基础样式;其余样式(`code.css` / `markdown.css` / `image.css` / `video.css` / `audio.css` / `txt.css` / `excel.css` / `pdf.css`)由对应渲染器首次 `render()` 时通过 `injectStyle()` 自动注入到 `` | `package.json` 同时导出了每个渲染器的独立 CSS 入口,便于宿主做精细化打包: ```json { ".": { "import": "./dist/docvu.js", "require": "./dist/docvu.umd.cjs" }, "./style.css": "./dist/styles/style.css", "./viewer.css": "./dist/styles/viewer.css", "./excel.css": "./dist/styles/excel.css", "./pdf.css": "./dist/styles/pdf.css" /* …其余渲染器同理 */ } ``` ## API 文档 ### createViewer(options) 创建预览器实例。 #### ViewerOptions | 参数 | 类型 | 默认值 | 说明 | |------|------|--------|------| | `target` | `HTMLElement \| string` | - | 挂载目标元素或选择器 | | `file` | `FileSource` | - | 文件源(URL / `File` / `Blob` / `ArrayBuffer`) | | `type` | `FileType` | 自动识别 | 手动指定文件类型,跳过推断 | | `filename` | `string` | - | 文件名(用于扩展名 / MIME 推断) | | `toolbar` | `boolean \| ToolbarConfig` | `true` | 是否显示外置工具栏 | | `theme` | `'light' \| 'dark' \| ThemeConfig` | `'light'` | 主题模式 | | `locale` | `'zh-CN' \| 'en' \| LocaleConfig` | `'zh-CN'` | 界面语言 | | `watermark` | `WatermarkConfig \| null` | `null` | 水印配置 | | `proxyUrl` | `string` | - | URL 前缀代理,拼接在 `file`(URL 形态)前用于跨域 / 鉴权下载 | | `requestAdapter` | `(url, options?) => Promise` | - | 自定义请求适配器,覆盖默认 `fetch` | | `allowCdn` | `boolean` | `true` | 是否允许渲染器在缺失本地依赖时回退到公共 CDN(内网部署请设为 `false`) | | `pdf` | `PdfConfig` | - | PDF 渲染器专属配置(透传给 EmbedPDF Snippet) | | `width` | `string \| number` | `'100%'` | 容器宽度 | | `height` | `string \| number` | `'100%'` | 容器高度 | | `className` | `string` | - | 附加到根容器的 CSS 类名 | | `style` | `Record` | - | 附加到根容器的内联样式 | | `renderOptions` | `{ zoom?: number; rotate?: number; page?: number }` | - | 初始渲染选项 | | `onReady` | `() => void` | - | 实例就绪回调 | | `onLoad` | `() => void` | - | 文件加载完成回调 | | `onError` | `(err: Error) => void` | - | 错误回调 | | `onDestroy` | `() => void` | - | 销毁回调 | #### PdfConfig(PDF 渲染器专属) ```ts interface PdfConfig { /** pdfium.wasm 自托管 URL(默认从 jsdelivr CDN 加载) */ wasmUrl?: string; /** 字体回退配置;传 null 禁用外部 CDN 字体回退 */ fontFallback?: null | { fonts: Record }; /** UI / 签名 webfont 配置;传 null 禁用外部 webfont 注入 */ fonts?: { ui?: null | { stylesheetUrl?: string; family?: string }; signature?: null | { stylesheetUrl?: string; families?: string[] }; }; } ``` #### 实例方法 ```ts interface ViewerInstance { // 生命周期 mount(target?: HTMLElement | string): void destroy(): void // 文件操作 setFile(file: FileSource, filename?: string): Promise getFile(): { filename: string; type: FileType; size: number } | null download(): void // 视图操作 zoom(scale: number): void // 0.1 ~ 5 rotate(degree: number): void // 任意角度,模 360 reset(): void // 重置缩放 + 旋转 fullscreen(enable?: boolean): void // 分页(渲染器支持时生效) prevPage(): void nextPage(): void gotoPage(page: number): void getPageInfo(): { current: number; total: number } | null // 配置 setTheme(theme: 'light' | 'dark'): void setLocale(locale: 'zh-CN' | 'en'): void // 运行时切换语言 setToolbar(config: ToolbarConfig): void // 运行时更新工具栏配置 setWatermark(config: WatermarkConfig | null): void // 运行时设置/移除水印 print(): void // 打印当前文档(优先渲染器原生打印,否则 HTML 打印) // 事件 on(event: 'ready' | 'load' | 'error' | 'destroy', handler: (...args: any[]) => void): void off(event: string, handler: (...args: any[]) => void): void // 状态 getState(): Record } ``` ## 支持的文件格式 | 类型 | 扩展名 | 状态 | 渲染器 | |------|--------|------|--------| | PDF | `.pdf` | ✅ 已支持 | `PdfRenderer`(EmbedPDF Snippet / PDFium WASM) | | Excel | `.xlsx` `.xls` `.xlsm` `.xlsb` `.xltx` `.ods` | ✅ 已支持 | `ExcelRenderer`(ExcelJS 优先 + SheetJS 兜底) | | CSV / TSV | `.csv` `.tsv` | ✅ 已支持 | `ExcelRenderer` | | 图片 | `.jpg` `.png` `.gif` `.webp` `.svg` `.bmp` `.tiff` `.ico` | ✅ 已支持 | `ImageRenderer` | | 视频 | `.mp4` `.webm` `.ogg` `.ogv` `.mov` | ✅ 已支持 | `VideoRenderer` | | 音频 | `.mp3` `.wav` `.ogg` | ✅ 已支持 | `AudioRenderer` | | Markdown | `.md` `.markdown` `.mdx` | ✅ 已支持 | `MarkdownRenderer` | | 纯文本 | `.txt` | ✅ 已支持 | `TxtRenderer` | | HTML | `.html` `.htm` `.xhtml` | ✅ 已支持 | `TxtRenderer` | | 代码 | `.js` `.ts` `.py` `.java` `.go` `.rs` `.vue` `.sql` 等 95+ 扩展名 | ✅ 已支持 | `CodeRenderer`(highlight.js) | | Word | `.docx` `.doc` | ✅ 已支持 | `DocxRenderer`(docx-preview) | | PPT | `.pptx` `.ppt` | ✅ 已支持 | `PptxRenderer`(@aiden0z/pptx-renderer) | | OFD | `.ofd` | ✅ 已支持 | `OfdRenderer`(@sharp9/ofdjs,Canvas2D 渲染) | | CAD | `.dxf` | ✅ 已支持 | `DxfRenderer`(@linkiez/dxf-renew,SVG 矢量渲染) | ## 渲染器能力与工具栏自动过滤 不同渲染器支持的交互能力不同(如视频不支持缩放/旋转/翻页)。SDK 通过 `RendererCapabilities` 接口声明各渲染器的能力,Viewer 在渲染完成后自动过滤工具栏按钮——只显示当前渲染器支持的按钮,避免无效操作。 ### 能力定义 ```ts interface RendererCapabilities { zoom: boolean; // 缩放(zoom-in / zoom-out / reset) rotate: boolean; // 旋转(rotate / reset) pageNavigation: boolean; // 翻页(prev / next / page-info) } ``` ### 各渲染器能力矩阵 | 渲染器 | 缩放 | 旋转 | 翻页 | 工具栏可见按钮 | |--------|:----:|:----:|:----:|----------------| | PDF | ✅ | ✅ | ✅ | 全部(缩放/旋转/翻页/全屏/下载/打印) | | Excel | ❌ | ❌ | ❌ | 全屏/下载 | | Word | ✅ | ✅ | ✅ | 全部 | | PPT | ✅ | ✅ | ✅ | 全部 | | OFD | ✅ | ✅ | ✅ | 全部 | | CAD(DXF) | ✅ | ✅ | ✅ | 全部 | | 图片 | ✅ | ✅ | ❌ | 缩放/旋转/全屏/下载 | | 视频 | ❌ | ❌ | ❌ | 全屏/下载 | | 音频 | ❌ | ❌ | ❌ | 全屏/下载 | | Markdown | ❌ | ❌ | ❌ | 全屏/下载 | | 代码 | ❌ | ❌ | ❌ | 全屏/下载 | | 纯文本/HTML | ❌ | ❌ | ❌ | 全屏/下载 | > **说明**:`fullscreen` / `download` / `print` 属于 Viewer 级能力,与渲染器无关,始终显示。`reset` 按钮在缩放或旋转任一支持时显示。切换文件时工具栏会自动重建以匹配新渲染器的能力。 ## 渲染器特性详解 ### PDF(PdfRenderer) - **引擎**:基于 [`@embedpdf/snippet`](https://www.npmjs.com/package/@embedpdf/snippet)(PDFium WebAssembly),非 pdf.js - **模块加载**:本地 `import('@embedpdf/snippet')` 优先 → CDN ESM(jsdelivr)兜底;模块级 Promise 单例,并发 `render()` 共用一次加载 - **UI 策略**:EmbedPDF 自带功能完整的工具栏 + 侧栏,PDF 模式下自动隐藏 DocVu 外置工具栏(`.dv-toolbar`),销毁时还原 - **预览聚焦**:通过 `disabledCategories` 禁用注释 / 表单 / 涂黑 / 搜索 / 评论 / 选择 / 截图 / 打印 / 导出 / 加密 / 全屏等编辑类能力,仅保留翻页 + 缩放 + 旋转 + 缩略图 - **国际化**:默认 `zh-CN`(fallback `en`) - **主题**:通过 EmbedPDF 原生 `setTheme()` 深合 DocVu 品牌蓝到 accent,运行时切换无需重建 - **API 桥接**:所有交互通过 PluginRegistry → `plugin.provides()` Capability 完成(`document-manager` / `scroll` / `zoom` / `rotate` 插件),而非直接调用 `EmbedPdfContainer` 方法 - **离线部署**:`allowCdn: false` + `pdf.wasmUrl` 自托管 + `pdf.fontFallback: null` 禁用外网字体回退,即可完全离线运行 - **加载状态**:absolute 定位的旋转 spinner + "正在加载 PDF…" 文案;30s 超时显示错误提示 ### Excel(ExcelRenderer) - **解析引擎**:ExcelJS 4.4.0(支持样式 / 合并 / 列宽 / 图片) - **加载策略**:本地 npm import → `window.ExcelJS` 全局 → jsdelivr UMD 动态 script tag - **虚拟滚动**:只渲染可视区域 + 自适应缓冲(基础 600px,快速滚动时线性扩到 1500px);万行级数据不卡顿 - 预计算累积行高 + 合并锚点;二分查找 O(log n) 定位行 - "幻影合并":起始行在可视区上方的合并单元格,在首可见行以缩减 `rowspan` 重新出现 - 跳过重建:小幅滚动时若已渲染范围仍覆盖视口,复用旧 DOM 避免白屏 - 离屏构建:新 `` 在 detached element 中拼装好后 `replaceWith` 切换,消除重建白闪 - **WPS DISPIMG 图片**:解析 `=DISPIMG("ID_xxx",1)` 公式提取图片 ID,三层匹配(文件名含 ID / 顺序兜底 / 浮动图片锚点)映射到 `xl/media`,渲染为 ``(120px 高、圆角阴影、棋盘透明底、暗色模式适配) - **大表兜底**:> 50k 行 / > 200 列自动截断 + 橙色警告 pill - **加载状态**:居中旋转 spinner + "正在加载…",主题色高亮,自动适配暗色 ### 代码(CodeRenderer) - 基于 highlight.js 语法高亮 - sticky 行号容器(`position: sticky`)保证滚动时行号常驻 - 代码体 `white-space: pre` + `line-height: 20px` 与行号对齐 - 95+ 扩展名映射 + 32+ 精确代码 MIME 类型识别 - 样式通过 `injectStyle()` 在首次 render 时注入,HMR 时按内容比对更新 ### Word(DocxRenderer) - **引擎**:基于 [`docx-preview`](https://github.com/VolodymyrBaydalka/docxjs)(浏览器端 DOCX → HTML DOM 渲染) - **模块加载**:本地 `import('docx-preview')` 优先 → jsdelivr ESM CDN 兜底;Vite 标记为 `external` - **分页**:`breakPages: true` 生成分页 DOM,兼容 Viewer 翻页 API - **格式限制**:`.doc`(二进制格式)不支持,命中时显示友好错误提示 - **加载状态**:居中旋转 spinner + "正在加载 Word 文档…",主题色高亮 - **暗色模式**:文档保持白底,容器背景通过 CSS 变量切换 - **缩放/旋转**:CSS `transform` on `.docx-wrapper`,top-center origin ### PPT(PptxRenderer) - **引擎**:基于 [`@aiden0z/pptx-renderer`](https://github.com/aiden0z/pptx-renderer)(浏览器端 PPTX → HTML/SVG DOM 渲染,支持形状/文本/图片/表格/图表/SmartArt/渐变/阴影/组合) - **模块加载**:本地 `import('@aiden0z/pptx-renderer')` 优先 → jsdelivr ESM CDN 兜底;Vite 标记为 `external` - **导航**:优先调用库原生 `goToSlide(index, options)` API(0-based,返回 Promise,支持 `ScrollIntoViewOptions`);库不可用时回退到 `scrollTop` 直接定位 - **页码跟踪**:监听库的 `slidechange` 事件(`detail.index`)精确跟踪当前页码;滚动监听作为 fallback,支持 `isConnected` 检测自动刷新失效引用 - **全屏兼容**:`goToSlide` 不依赖缓存的 DOM 元素引用,全屏 re-render 后仍可正常翻页 - **格式限制**:`.ppt`(二进制格式)不支持,命中时显示友好错误提示 - **加载状态**:居中旋转 spinner + "正在加载 PPT 文档…",主题色高亮 - **暗色模式**:幻灯片保持原底色,容器背景通过 CSS 变量切换 - **缩放/旋转**:CSS `transform` on 幻灯片容器,top-center origin ### OFD(OfdRenderer) - **引擎**:基于 [`@sharp9/ofdjs`](https://github.com/isee15/ofdjs)(OFD GB/T 33190-2016 → HTML5 Canvas2D 渲染) - **模块加载**:本地优先 + CDN 兜底(respecting `allowCdn`),Vite 标记为 `external` - **分页**:OFD 页面逐页渲染到 Canvas,支持翻页导航 - **缩放/旋转**:CSS `transform` on 页面容器 - **样式**:`--dv-ofd-*` CSS 变量统一管理加载态、错误态、页面阴影、暗色主题 ### CAD / DXF(DxfRenderer) - **引擎**:基于 [`@linkiez/dxf-renew`](https://github.com/linkiez/DXF-Renewed)(DXF 文本 → SVG 矢量图形渲染,支持 18+ 实体类型) - **模块加载**:本地优先 + CDN 兜底(respecting `allowCdn`),Vite 标记为 `external` - **缩放/旋转**:CSS `transform` on SVG 容器 - **样式**:`--dv-dxf-*` CSS 变量统一管理加载态、错误态、SVG 阴影、暗色主题 ## 开发 ```bash # 安装依赖 npm install # 启动开发服务器,浏览器访问 http://localhost:5173/demo/index.html 即可预览 demo npm run dev # 类型检查 + 构建(ES 多入口 + UMD/IIFE 单入口两次构建) npm run build ``` 构建说明: - `vite build` 产出 ES 格式(`dist/docvu.js` + `dist/styles/*.css` + `dist/index.d.ts`) - `vite build --mode umd` 产出 UMD / IIFE(`dist/docvu.umd.cjs` + `dist/docvu.iife.js`) - 渲染依赖(`@embedpdf/snippet`、`exceljs`、`docx-preview` 等)均标记为 `external`,由宿主 `node_modules` 或 CDN 提供,不打入产物 - `emptyOutDir: !isUmdBuild` 避免 UMD 构建清空 ES 产物 - 发布包通过 `package.json` 的 `files` 字段排除 `dist/**/*.map`,仅发布运行时必要文件 ## 第三方依赖与致谢 DocVu 的渲染能力建立在多个优秀的开源库之上。所有依赖均为**宽松许可证**(MIT / Apache-2.0 / BSD-3-Clause),与本项目的 MIT 许可证兼容。 以下为各渲染器使用的第三方库: | 渲染器 | 第三方库 | 版本 | 许可证 | 加载策略 | |--------|----------|------|--------|----------| | PDF | [`@embedpdf/snippet`](https://www.npmjs.com/package/@embedpdf/snippet)(内嵌 PDFium) | ^2.15.0 | MIT(PDFium 为 Apache-2.0) | 本地 npm import → jsdelivr CDN 兜底 | | Excel | [`exceljs`](https://github.com/exceljs/exceljs) | ^4.4.0 | MIT | 本地 import → `window.ExcelJS` 全局 → jsdelivr UMD | | Word | [`docx-preview`](https://github.com/VolodymyrBaydalka/docxjs) | ^0.3.3 | Apache-2.0 | 本地 import → jsdelivr CDN | | PPT | [`@aiden0z/pptx-renderer`](https://github.com/aiden0z/pptx-renderer) | ^1.2.4 | Apache-2.0 | 本地 import → jsdelivr CDN | | OFD | [`@sharp9/ofdjs`](https://github.com/isee15/ofdjs) | ^0.1.0 | Apache-2.0 | 本地 import → jsdelivr CDN | | CAD | [`@linkiez/dxf-renew`](https://github.com/linkiez/DXF-Renewed) | ^7.6.0 | MIT | 本地 import → jsdelivr CDN | | 代码高亮 | [`highlight.js`](https://github.com/highlightjs/highlight.js) | ^11.9.0 | BSD-3-Clause | 本地 import → `window.hljs` 全局 → cdnjs CDN;主题 CSS 已内联打包 | | ZIP 解压 | [`jszip`](https://github.com/Stuk/jszip) | 3.10.1 | MIT(双许可,选用 MIT) | 本地 import(docx-preview 传递依赖)→ jsdelivr CDN | > **说明**:上述渲染库均通过 `external` + 动态 `import()` 按需加载,**不打入 SDK 主产物**。宿主项目已安装时走本地打包,未安装且 `allowCdn !== false` 时从公共 CDN 兜底加载。 > > `highlight.js` 主题 CSS(github / github-dark)已在构建时内联打包,无需额外引入;JS 引擎遵循三级加载策略,`npm install @docvu/docvu` 时通过 `optionalDependencies` 自动安装。 完整的第三方版权声明与许可证文本见 [`NOTICE`](./NOTICE) 文件。 ## License [MIT](./LICENSE) © DocVu Contributors 本项目包含的第三方组件各自保留其原始许可证,详见 [`NOTICE`](./NOTICE)。