ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Vue3文件预览全攻略:Word、Excel、PDF、图片、TXT一网打尽

Vue3文件预览全攻略:Word、Excel、PDF、图片、TXT一网打尽 1. 需求拆解5类文件格式背后是5条完全不同的技术路线做后台管理系统的人迟早都会撞上文件预览这个需求。尤其是当业务方甩过来一句我们系统里要能看Word、Excel、PDF、图片和TXT时第一反应往往是找个插件一把梭。但真正动手之后才会发现这5类格式在浏览器里的预览方案完全不是一个量级的问题混在一堆谈Vue3文件预览的文章里细节差距大得惊人。先把这个需求的本质拆开看图片和TXT是浏览器原生能力就能覆盖的PDF在大部分现代浏览器里也可以直接扔给内置阅读器但Word的docx格式本质上是一个zip压缩包里面是一堆XML文件Excel的xlsx同样如此。浏览器不可能原生解析这两种格式必须借助第三方库把二进制内容解析成HTML结构再渲染到页面上。所以Vue3实现文件预览这句话翻译过来其实是四件事调浏览器API、用PDF原生能力、接两个解析库、处理各种边界异常。我在实际项目里见过不少团队在这个需求上翻车最典型的就是拿iframe直接怼docx路径结果浏览器要么直接下载要么显示乱码。还有一些团队为了省事把所有文件都丢给微软或金山的在线预览服务虽然省了开发量但文件要走第三方服务器涉密数据和内网系统直接pass。所以这篇文章的重点就是讲清楚在Vue3项目里怎么用本地解析的方式把这5类文件完整预览出来不依赖外部服务数据不出内网。1.1 5类格式的解析难度差异先说个直观的对比文件类型浏览器原生支持需要第三方库实现难度核心痛点图片是否低大图加载性能TXT是否低编码识别PDF部分支持可选低兼容性与内嵌字体Word(docx)否是高样式还原、复杂排版Excel(xlsx)否是中合并单元格、公式之所以说它是五条技术路线是因为每个格式的渲染机制完全不同。图片用img标签TXT用Blob对象转URLPDF如果只要求基础预览可以直接用iframe但如果你想控制翻页、缩放、文本选择就得引入PDF.js。Word和Excel则必须走解析-转换-渲染三步解析库把二进制文件里的XML和文本读出来生成HTML或JSON结构再挂到页面上。1.2 主流方案对比与选型结论在开始写代码之前我把市面上的方案都过了一遍包括用第三方在线预览服务、用docx-preview、用SheetJS、用PDF.js以及用浏览器原生iframe硬扛。最后根据实际项目约束选型结论如下Word用docx-preview目前社区维护最活跃、还原度最高的开源docx渲染库支持页眉页脚、表格、图片、目录等大部分复杂元素。Excel用SheetJS即xlsx库解析xlsx/xls文件后手动渲染成HTML表格。如果你需要保留单元格样式、合并单元格、列宽行高还得在渲染层自己做映射。PDF优先iframe配合浏览器内置PDF阅读器如果产品要求自定义工具栏翻页、缩放、搜索再切换到PDF.js。图片直接img标签objectURL注意内存释放。TXTFileReader读文本配合编码检测处理GBK编码。这个方案的组合拳能覆盖绝大多数业务场景而且不依赖外部服务Windows和macOS平台通吃。2. 环境准备Vue3项目搭建与依赖版本锁定既然标题是Vue3实现文件预览那我们默认你已经有一个Vue3的项目基础。如果没有用Vite初始化一个最省事。npm create vitelatest file-preview-demo -- --template vue-ts cd file-preview-demo npm install接下来是引入预览相关的核心依赖。这里必须强调版本锁定的问题我在这上面栽过跟头——docx-preview和xlsx这两个库的API在版本迭代里变过好几次直接npm install latest版本很可能导致老文章的示例代码跑不通。npm install docx-preview3.0.1 npm install xlsx0.18.5选择这些版本的原因很直接docx-preview的3.0.1版本废弃了旧版的renderAsync返回值同时修复了在Vue3下组件卸载时可能报错的问题xlsx的0.18.5是最后一代完全免费且稳定支持xls格式的版本2023年之后的版本把一些解析能力挪到了付费版里但对我们前端预览xlsx的场景来说0.18.5完全够用。2.1 基础页面结构与文件上传入口为了后续演示方便先搭一个最基础的上传入口。我的做法是做一个隐藏的input标签接收File对象然后统一走一个preview方法。template div classpreview-container input typefile multiple changehandleFileChange / FilePreview :filecurrentFile / /div /template script setup langts import { ref } from vue import FilePreview from /components/FilePreview.vue const currentFile refFile | null(null) function handleFileChange(e: Event) { const input e.target as HTMLInputElement if (input.files input.files.length 0) { currentFile.value input.files[0] } } /script后面章节里的预览组件都是围绕这个File对象来设计的。用File对象而不是文件URL字符串做入参有一个额外的好处预览逻辑可以完全通用化不论文件来自上传控件、来自接口返回的二进制流还是来自拖拽区域最终都能统一转成File或Blob处理。2.2 TypeScript类型声明与全局组件注册如果你的项目用了TypeScriptdocx-preview和xlsx这两个库都需要额外的类型声明或全局d.ts处理。docx-preview 3.x版本自带类型定义一般不用额外处理但xlsx 0.18.5的类型定义在某些版本里不够完整我习惯在项目的src/types目录下自己补充一个声明文件。declare module xlsx { export interface WorkBook { SheetNames: string[] Sheets: { [sheet: string]: WorkSheet } } export interface WorkSheet { !ref?: string !merges?: any[] [cell: string]: any } export function read(data: any, opts?: any): WorkBook export function utils: any }这段声明看着简单但解决了两个实际问题一是避免TS编译报错二是通过接口定义把工作簿、工作表、合并单元格这些概念在代码里明确下来后面写渲染逻辑的时候思路清晰很多。3. PDF/图片/TXT不依赖第三方库的白嫖方案这三种格式其实可以合并成一个大章节来讲因为它们的技术核心都是同一个——把File对象转成浏览器能直接消费的URL。区别只在于消费这个URL的载体不同。3.1 PDF预览iframe与原生阅读器的取舍对于PDF最省事的方案是走iframetemplate iframe :srcpdfUrl classpdf-frame/iframe /template script setup langts import { ref, watch, onBeforeUnmount } from vue const props defineProps{ file: File }() const pdfUrl ref() watch( () props.file, (file) { if (pdfUrl.value) { URL.revokeObjectURL(pdfUrl.value) } pdfUrl.value URL.createObjectURL(file) }, { immediate: true } ) onBeforeUnmount(() { if (pdfUrl.value) { URL.revokeObjectURL(pdfUrl.value) } }) /script用iframe的好处是能直接复用Chrome、Edge、Firefox内置的PDF阅读器翻页、缩放、打印这些功能全部白送。代价是UI风格和浏览器强绑定而且无法在页面上嵌入自定义的PDF操作按钮。Chrome对iframe内PDF的跨域限制比较敏感但用objectURL生成的地址是同源的所以不存在这个问题。3.2 图片预览大图处理与内存管理图片预览的逻辑最简单一个img标签配上objectURL就能跑。但有两个细节值得多说一句。第一个是超大图片的加载性能。如果你预览的是一张几十MB的高清设计稿直接扔给img标签会导致内存飙升严重的直接白屏崩溃。稳妥的做法是先读图片的尺寸和大小超过阈值比如宽度超过2000px或大小超过5MB就做一次canvas压缩把压缩后的base64或新生成的objectURL传给img。第二个是内存释放。用URL.createObjectURL生成的临时URL在组件卸载或者文件切换时如果不调用URL.revokeObjectURL会造成内存泄漏。在后台管理系统里用户频繁切换文件一天下来内存多出几百MB很常见。这个习惯在所有的预览组件里都要保持。3.3 TXT预览编码检测是最大的坑TXT文件看起来最没有技术含量但实际上最容易出问题。原因很简单中文环境的TXT文件经常是GBK或GB2312编码而浏览器默认按UTF-8解析于是打开全是乱码。const text await file.text() // 这一步默认按UTF-8解码如果你不做编码检测读出来的文本在Windows系统上传的文件上大概率是乱码。我的解决方案是用jschardet库先做编码识别再按识别结果解码npm install jschardetimport { detect } from jschardet async function readTextWithEncoding(file: File) { const buffer await file.arrayBuffer() const uint8Array new Uint8Array(buffer) const detected detect(uint8Array) const encoding detected.encoding || UTF-8 // TextDecoder支持常见的GBK、GB18030编码 return new TextDecoder(encoding).decode(uint8Array) }注意TextDecoder支持的编码集合是有限制的GB18030和GBK都能解但是Big5、Shift_JIS这类编码在部分浏览器内核下支持不够稳定。实测下来国内常见的TXT文件用这个方案基本能全覆盖。还有一个容易被忽略的细节文件开头可能带有BOM头解码之后要记得去掉BOM字符否则第一行会多出一个肉眼不可见的字符影响后续字符串处理。4. Word预览docx-preview插件的接入与样式还原Word预览是整个需求里最难啃的一块硬骨头。docx格式本质上是一个zip压缩包里面包含word/document.xml、word/styles.xml、word/media/目录等多个部件浏览器没法直接渲染。docx-preview这个库做的事情就是把docx里的XML结构和样式读出来转换成HTML DOM元素再插入到指定容器中。4.1 为什么不用微软Office在线预览或第三方服务我在选型的时候专门对比过几条路线。微软Office Web Viewer和金山文档的在线预览服务确实能提供几乎100%的还原度而且省掉所有解析工作。但它们的硬伤也明显文件要上传到第三方服务器内网系统的文件安全直接破防而且这些服务的URL有长度限制和格式限制动辄几十MB的Word文档很可能被拒。docx-preview虽然做不到100%像素级还原但它本地解析、本地渲染文件不出浏览器安全性完全可控。还有一个关键点docx-preview对docx格式支持很好但对老旧的doc格式2003版及更早无能为力。如果你必须兼容doc格式可以在后端用LibreOffice或ONLYOFFICE转成docx再返回给前端或者直接提示用户上传docx。4.2 核心渲染逻辑与代码实现template div refwordContainer classword-preview v-loadingloading/div /template script setup langts import { ref, watch, onBeforeUnmount } from vue import { renderAsync } from docx-preview const props defineProps{ file: File }() const wordContainer refHTMLDivElement() const loading ref(false) watch( () props.file, async (file) { if (!file || !wordContainer.value) return loading.value true try { wordContainer.value.innerHTML // renderAsync接受Blob或ArrayBuffer等多种输入类型 await renderAsync(file, wordContainer.value, null, { className: docx-preview, inWrapper: true, ignoreWidth: false, ignoreHeight: false, ignoreFonts: false, breakPages: true, ignoreLastRenderedPageBreak: true, experimental: true, trimXmlDeclaration: true, useBase64URL: true, useStyleTags: true, }) } catch (e) { console.error(Word预览渲染失败, e) } finally { loading.value false } }, { immediate: true } ) onBeforeUnmount(() { if (wordContainer.value) { wordContainer.value.innerHTML } }) /scriptrenderAsync的options参数里有四个选项是必须留意的inWrapper是否把渲染内容包裹在一个div里。建议设为true方便后续通过CSS控制预览区的宽度和滚动。ignoreWidth和ignoreHeight是否忽略文档里设置的页面宽高。如果设为false渲染结果会严格按A4纸的比例撑开在屏幕上看可能需要横向滚动条设为true则会自动缩放适配容器宽度更适合屏幕预览。breakPages是否分页。设为true时每页会用pagesheet的div隔开视觉上更接近真实文档但页面数量多时渲染性能会下降。useBase64URL是否把文档内的图片转为base64。如果为false有些图片可能无法正常显示。4.3 样式还原实测页眉页脚、表格、图片一个都不能少我用一份包含页眉、页脚、三栏表格、多张图片、目录的docx文件做了实测。docx-preview 3.0.1的还原度相当不错页眉页脚的定位基本准确表格边框和单元背景色能正常显示图片也能按文档里的尺寸渲染出来。有两个渲染不完整的情况需要业务层面接受 第一艺术字、文本框这类特殊元素可能被渲染成近似样式毕竟前端没有Office的排版引擎能做到结构正确已经不易 第二部分字体比如方正系列如果用户电脑没有安装浏览器会用系统默认字体替代视觉上跟原文档有一定差距。解决办法是把常用字体用font-face加载到前端项目里但会显著增加前端资源体积非必要不推荐。5. Excel预览SheetJS的表格渲染与样式处理Excel的预览走的是另一条思路。xlsx库SheetJS社区版能做的是把xlsx文件里的数据解出来包括单元格的值、单元格的坐标范围、合并单元格信息、列宽行高但20列以上的样式还原就别指望了——它连单元格背景色和字体颜色都只能解出很有限的一部分字体名、边框、对齐方式等大部分样式会丢失。5.1 数据解析工作簿、工作表与单元格import * as XLSX from xlsx function parseExcel(file: File) { return new Promise((resolve, reject) { const reader new FileReader() reader.onload (e) { try { const data new Uint8Array(e.target?.result as ArrayBuffer) const workbook XLSX.read(data, { type: array }) resolve(workbook) } catch (error) { reject(error) } } reader.readAsArrayBuffer(file) }) }XLSX.read返回的workbook对象里SheetNames是工作表名称的数组Sheets是每个工作表名称到工作表对象的映射。拿到工作表对象之后需要根据它的!ref属性来确定数据范围!ref的值类似A1:E20表示从A1到E20有数据。遍历单元格的方式是用工具函数把!ref拆成行列坐标然后逐格取值function sheetToData(sheet: XLSX.WorkSheet) { const range XLSX.utils.decode_range(sheet[!ref] || A1) const rows: any[][] [] for (let rowNum range.s.r; rowNum range.e.r; rowNum) { const row: any[] [] for (let colNum range.s.c; colNum range.e.c; colNum) { const cellAddress XLSX.utils.encode_cell({ r: rowNum, c: colNum }) const cell sheet[cellAddress] row.push(cell ? cell.v : null) } rows.push(row) } return rows }这里有个小坑直接用两层循环去遍历A1到E50这种范围在大表格上性能是可以接受的但如果表格有几万行一次性全部渲染成DOM会导致页面卡死必须做虚拟滚动或懒加载。我一般限制预览的渲染行数超过500行就用分页按钮控制。5.2 合并单元格处理和样式映射合并单元格是最影响阅读体验的一个点也是很多预览组件容易忽略的。工作表对象里有个!merges属性是一个数组每个元素包含s起始行列和e结束行列。渲染时用CSS的rowspan和colspan来解决td v-if!isMergedCell(row, col) :rowspanrowspan(row, col) :colspancolspan(row, col) {{ cellValue(row, col) }} /td判断逻辑是遍历merges当前单元格如果是某个合并区域的起始点就输出一个带rowspan和colspan的td如果不是起始点就完全跳过不渲染。这样能保证表格结构正确。列宽与行高的处理上SheetJS能读出workbook.Sheets[sheetName][!cols]和!rows分别对应列宽和行高数组可以把它们映射成td的style。不过实测下来列宽数值单位是字符数不是像素需要乘以一个系数通常7个像素左右转换否则渲染出来的表格比例跟Excel里看到的会有偏差。我习惯在转换时不处理行高只处理列宽因为行高大多由内容撑开强行设置数值容易造成文字截断。5.3 Excel渲染的完整代码template div classexcel-preview v-loadingloading div classsheet-tabs button v-for(name, index) in sheetNames :keyname :class{ active: index activeSheet } clickswitchSheet(index) {{ name }} /button /div div classsheet-container table tr v-for(row, rowIndex) in tableData :keyrowIndex td v-for(cell, colIndex) in row :keycolIndex :rowspangetRowspan(rowIndex, colIndex) :colspangetColspan(rowIndex, colIndex) v-show!isMergedHidden(rowIndex, colIndex) {{ cell }} /td /tr /table /div /div /template这个组件的核心就是保持tableData、sheetNames、merges三个数据结构的同步。实际渲染时如果有合并单元格还是一个单元格输出rowspan/colspan但要注意表格的总列数必须统一否则行与行之间对不齐。用这段代码实测一份带合并单元格、数字格式、超链接的销售报表大部分情况能正常显示但有两个已知缺陷一是单元格里的数字格式如百分比、日期格式会被解析成原始数值需要自己做格式化二是条件格式图标不会渲染出来因为SheetJS社区版取不到这些信息。6. 组件封装一个通用的FilePreview组件的实现细节把前面几种方案的代码整合进一个FilePreview组件里是这个需求的最终形态。组件的设计上有几个点需要提前规划好否则后期加新格式会非常痛苦。6.1 Props与事件的语义设计我的组件接口长这样interface FilePreviewProps { file: File | null // 可选不传则根据file.type自动判断 previewType?: word | pdf | excel | image | txt // 可选Excel预览时的最大渲染行数 excelMaxRows?: number // 可选Word预览时是否分页 wordBreakPages?: boolean }不传previewType时组件内部根据file.type或file.name的扩展名做判断。这里有个细节很多系统的上传组件会把file.type置空所以判断逻辑必须兼容后缀名。我的判断优先级是先看file.type再看file.name的扩展名最后兜底用预览器的魔数判断读文件头几个字节判断真实格式。6.2 动态加载与按需渲染如果FilePreview组件把所有格式的预览逻辑都一次性打包主包体积会明显增加。我采用的是defineAsyncComponent方式做动态加载让Word和Excel的解析库只在真正需要时才加载script setup langts import { computed, defineAsyncComponent, h } from vue const WordPreview defineAsyncComponent(() import(/components/WordPreview.vue)) const ExcelPreview defineAsyncComponent(() import(/components/ExcelPreview.vue)) const PdfPreview defineAsyncComponent(() import(/components/PdfPreview.vue)) const ImagePreview defineAsyncComponent(() import(/components/ImagePreview.vue)) const TxtPreview defineAsyncComponent(() import(/components/TxtPreview.vue)) const currentComponent computed(() { const type resolveType(props.file) switch (type) { case word: return WordPreview case excel: return ExcelPreview case pdf: return PdfPreview case image: return ImagePreview case txt: return TxtPreview default: return null } }) /script这种做法的副作用是首次打开某个格式时会有短暂的白屏加载时间我一般配合loading组件让用户感知到加载进度。也可以考虑预加载策略——用户上传文件后立即预加载对应格式的解析库这样用户点击预览时基本零等待。6.3 错误兜底与用户提示文件预览的功能上线后你会发现用户传上来的文件五花八门很多根本不符合后缀名对应的格式。比如把一个doc文件改名成docx或者把一个csv文件传上来。我的策略是在预览前先做文件头魔数校验能识别真实格式的就按真实格式渲染识别不了的给一个友好的错误提示而不是让用户看到一堆乱码或一个空白页面。这部分的代码可以写在组件的统一错误处理逻辑里捕获所有子组件抛出的异常加上一个尝试下载原文件的按钮给用户留一条退路。7. 踩坑记录从乱码到崩溃的完整排查链路这部分是我最想写的因为实际开发里真正耗时间的不是写逻辑而是排查各种奇怪的问题。7.1 大文件导致的浏览器内存溢出第一次用docx-preview渲染一份120MB的Word文档时浏览器直接卡死页面变成白屏。排查下来问题出在两点一是renderAsync一次性把整份文档的DOM都插入容器里文档里有上百页的时候DOM节点数量巨大二是页面分页模式breakPages: true下每个分页都会额外生成一个包装div节点数量翻倍。解决方案是双管齐下前端限制预览文件的大小超过50MB的文件给出提示让用户下载后本地查看后端如果可能把docx转成pdf再预览pdf的渲染性能远好于docx的DOM渲染。组件的容流提示也要讲究不能只提示一句文件过大而是给出明确的阈值和替代方案。我的文案是当前文档超过50MB为保证预览性能请下载后使用Office软件打开。7.2 Excel预览时中文乱码xlsx.read解析出来的单元格值出现乱码排查了半天最后发现问题出在FileReader读取格式上。用file.text()去读xlsx文件会把二进制内容按UTF-8解码但xlsx是二进制格式这种方式会破坏数据完整性。正确的读取方式是readAsArrayBuffer然后使用XLSX.read(data, { type: array })。如果用了base64方式也要注意FileReader的readAsDataURL在读取大文件时会占大量内存arrayBuffer方案更稳妥。这个坑的典型特征是小文件几十KB偶尔能正常解析大一点的文件就乱码或直接报错因为base64或text编码在数据量变大时更容易产生损坏。7.3 Word样式丢失从渲染不完全到文字重叠docx-preview渲染出来的Word文档样式丢失的来源有三个层级。第一个层级是整个文档的默认字体丢失。docx里的字体名称存在styles.xml里渲染时如果浏览器找不到对应字体会直接用默认字体替代效果就是整篇文档的字体都不太对但不影响阅读。第二个层级是块级元素的间距丢失。段落与段落之间的行距、段前段后距如果在文档里用的是某个特定的样式名称而docx-preview没有完全解析到会出现整篇文档挤在一起的观感。第三个层级是最头疼的某些docx里的制表位tab在渲染时被忽略了导致原本对齐的内容全部错位。我遇到过一份带目录的标书目录里的页码全部挤在一起。排查时先确认styles.xml里的tabLeader是否被读到了docx-preview对tab的支持一直不是很完美只能尽量规避——建议用户在上传前把目录转成静态文本。7.4 你尝试预览的文件可能对你的计算机有害这个安全提示这个提示在Windows系统上用iframe预览PDF时特别常见尤其是文件来自网络位置时。它的本质是Windows的Mark of the WebMOTW机制在起作用系统检测到文件来源不是本地而是网络或外部设备就会弹出安全警告。出现这个提示不代表代码有bug而是浏览器的安全策略。解决方案有三个方向 第一在iframe的sandbox属性上做文章但实战下来效果有限 第二用embed标签或者直接通过fetch把文件以blob方式读取再生成objectURL能规避部分场景的警告 第三最彻底的方式是改用PDF.js这类前端解析库不走浏览器内置PDF阅读器系统根本没有机会触发MOTW逻辑。我最后选了第三条路顺带解决了iframe里PDF工具栏无法定制的问题方案上算是把这次踩坑转化成了产品能力的加分项。8. 扩展方向移动端适配、加密文件与大表格优化完成基础的文件预览功能只是第一步真放到生产环境里会有几个衍生需求陆续冒出来。8.1 移动端适配的几个问题手机上做文件预览首先要面对的是iframe在移动端浏览器上的表现差异。iOS的Safari和安卓的Chrome对iframe内PDF的展示逻辑不同有些安卓浏览器会直接调起外部PDF应用有些直接显示空白。所以移动端PDF预览建议直接用PDF.js渲染canvas。Word和Excel的移动端预览docx-preview和SheetJS本身不关心屏幕宽度但渲染出来的DOM是宽度固定的需要用transform: scale做缩放适配或者用CSS zoom属性做整体缩放。缩放的比例根据容器宽度和内容宽度的比值计算代码大约是这样的const rect container.getBoundingClientRect() const scale rect.width / contentScrollWidth container.style.transform scale(${scale})8.2 服务端转换兜底当纯前端解析不够用的时候纯前端解析有一个无法绕开的边界老式的doc格式、老式的xls格式、WPS特制的加密格式第三方库往往无法解析或者解析效果不理想。我的实际操作中有两种文件类型会让docx-preview和SheetJS崩溃或者解析为空一种是用WPS生成的部分docx文件命名空间不规范另一种是加密的Office文件。遇到这种情况一个可靠的后端兜底方案是前端解析失败时把文件传给后端后端用OnlyOffice DocumentServer或LibreOffice做格式转换转换成pdf或者html转完再把结果回传前端展示。这个方案需要后端参与但它是文件预览体系里最稳的兜底手段。如果不想引入重型的Office服务轻量级的办法是用Pandoc做格式转换虽然对复杂排版的还原度不如OnlyOffice但胜在部署简单。8.3 预览权限与缓存策略最后提一个容易被忽略的点文件预览的权限控制。很多系统的文件URL是临时生成的或者带有鉴权参数。如果你直接把URL传给docx-preview或iframe而该URL又需要带token访问很可能因为跨域或安全策略加载失败。我推荐的做法是前端统一通过fetch把文件以arrayBuffer方式从后端取回来自己构建Blob再转objectURL这样既能携带自定义请求头完成鉴权又能统一走本地解析逻辑。同时可以通过axios的cancelToken或AbortController实现预览取消用户快速切换文件时不会发出多个无意义的请求。const response await fetch(/api/file/preview?id${fileId}, { headers: { Authorization: Bearer ${token} } }) const blob await response.blob() const file new File([blob], fileName, { type: blob.type })这套玩法做下来整个文件预览功能就基本完整了。每次接到做个文件预览需求时我都会把上面这套方案过一遍——先用浏览器原生能力解决PDF、图片、TXT再用docx-preview和SheetJS覆盖Word和Excel最后再用服务端转换兜底解决旧格式和加密文件。折腾过几个项目之后你会发现所谓的文件预览本质上不是去找一个万能插件而是理解每种格式的解析原理然后在合理的位置选对工具把各种异常情况都收拾干净。
返回列表