纯前端的文档预览功能,是非常常见的需求,但就是这么简单的需求,难住了许多可爱的小伙伴们。别急,先访问一下解决方案,给你一个惊喜,再往下看:
文件在线预览DEMO
服务器文件预览DEMO
Vue3纯前端文档预览演示
项目最新进展(2023年12月1日):
1. Vue2版本代码全面同步Vue3所有特性,支持vite快速开发,bug修复和功能整合
2. 全版本正式发布中央仓库,搜索 @flyfish-group/file-viewer,基于Apache2.0协议免费供大家使用
3. 新增支持 xls,xlsm, xlsb, csv, ods, fods, numbers 等表格格式。
4. 中央仓库直达:@flyfish-group - npm search
5. Vue2版本组件仓库直达:@flyfish-group/file-viewer - npm
项目进展(2023年4月10日):
1. Vue3版本重构了Xlsx模块,使用Worker加载,增加了体验性,能够秒级打开千万行的Excel
2. 增加了Markdown文档的渲染,能够美观的渲染md文档,使用了github风格
4. 新版文档增加视频演示,更直观展示功能。
项目进展(2023年4月4日):
1. Vue3+TypeScript+Vite版本发布,完全重构,性能飞跃,超高代码质量
2. 重构了Xlsx对于主题颜色的获取和计算,能够完美显示颜色
3. 重构了Pptx底层部分逻辑,解耦了图表部分,并优化了显示性能
4. 新版文档已经上线,demo部分替换部署了Vue3版本
2023年2月28日全面升级说明
鉴于很多朋友呼吁文档的问题,目前使用文档已更新,请参考
使用文档
本次更新属于突破更新,完成了项目组件化改造,嵌入项目中使用更加容易,具体请拉取最新代码体验一下吧!
==更新日志==
1. 优化了pptx嵌套块溢出效果,比之前好很多
2. 增加了文件标题显示
3. 进行了组件化拆分设计,提供标准的Vue组件,方便接入
4. 优化了底层的一些代码,运行更加稳定
== 公众号上线!==
此外,博主的公众号上线了,大家在微信搜索 "飞鱼开源"。关注“飞鱼开源WorkShop”公众号,可以获取最新源码,同时不定期更新技术福利!
有大家的支持我才有更新的动力,感谢大家一直以来的支持!❤❤❤
仓库地址: https://git.flyfish.group,请下载过资源的大家注册后获取最新源码!
2022年8月1日更新,重大升级。
1. 重构大部分pptx逻辑,优化背景样式,块文字样式和图表。
2. 优化PDF展现逻辑,基于官网demo使用官方pdfViewer组件实现懒加载,虚拟滚动,大幅度提高性能,可以秒开超大PDF文件!
3. 优化框架和升级依赖版本
福利:注册git私库并发送账号给博主,博主会帮忙开放本项目的git仓库权限,永久更新!记得是下载过资源的小伙伴哦,开发不易,请予以点滴支持,不尽感激!
git仓库地址:飞鱼开源工作室
2022年5月31日更新。增加文件url输入预览,可以访问文件在线预览DEMO体验。由于很多小伙伴提的问题都是关于服务器URL预览文件怎么预览,这次的demo集成了这部分功能,大家可以参照源码进行理解和修改。
因demo使用ajax加载,在测试时请保证文件资源响应Header包含允许跨域的头部。建议头部如下:
Access-Control-Allow-Origin * Access-Control-Allow-Headers X-Requested-With Access-Control-Allow-Methods GET 功能入口如下:
word文档预览
Excel文档预览
PPT文档预览
PDF文档预览
Markdown预览
图片预览
文本预览
视频预览
看完了之后,废话不多说,来给大家梳理梳理实现思路。
笔者在接到这个功能需求后,对市面上目前的实现方案进行了归纳和梳理,不外乎就三种:
到此为止,所有的方案都被pass掉了,非常绝望。无果后,我搭上梯子,疯狂Google,终于找到了一个jquery的开源插件,叫做officeToHtml,出于对开源的尊重,这里提供一下人家的访问链接:OfficeJs | Demos
这个开源项目非常好用,引用它的demo就能直接预览主流格式,但是它是基于JQuery的。事实上,当时我都已经通过这个方案实现了,结果我们领导说不是Vue,而且用的组件也太老了,强行pass掉了。现实总是残酷的,看着我头顶所剩不多的秀发,深深叹了口气,准备自己再次开整。
有了国外大佬的思路提供,我的思路也渐渐清晰:
OK,思路清晰了,我们开始撸代码。
大佬的框架已经老得不被待见了,大致整理后,笔者找到的最贴近且效果最好的框架都在下面的表里了:
powerpoint(pptx)
pptxjs改造开发
升级后的组件完全兼容npm,唯一不兼容的pptxjs也被我改造了,能够完美兼容。以下是package.json中相关的依赖。
"@handsontable/vue": "^11.1.0", "docx-preview": "^0.1.8", "exceljs": "^4.3.0", "handsontable": "^11.1.0", "pdfjs-dist": "^2.12.313", "v-viewer": "^1.6.4", "vue": "^2.6.11"
框架找好了,接下来我们开工。老样子,用vue-cli创建一个hello-world项目,把脚手架初始化出来。如果没安装过,先全局安装一下:
npm install -g @vue/cli-service-global
创建项目,名字就叫file-viewer吧!
cd ~/Projects vue create file-viewer
然后我们在 src/components/HelloWorld.vue中,给他加一个容器,用于承载文档视图。再弄一个简单的loading容器,ok。
注意,这里的 @/components/util 是一些常用工具类,主要做二进制数据和字节码、字符串互转的。当然,文档渲染入口也在里面,我们后面说。
Vue在线文档查看器
正在加载中,请耐心等待...
写好容器后,下一步就是重头戏,笔者这里使用匹配模式简单实现了一个渲染入口,代码如下:
// 导入渲染器 import renders from './renders'; // 渲染入口函数,包含字节数组、文件类型、目标容器 export async function render(buffer, type, target) { const handler = renders[type]; if (handler) { return handler(buffer, target); } return renders.error(buffer, target, type); }
具体渲染逻辑我们用声明式的方式进行配置,统一放置在vendors目录下,像这样:
之后我们写一个策略配置器,去统一导入这些模块:
import { defaultOptions, renderAsync } from 'docx-preview'; import renderPptx from '@/vendors/pptx'; import renderSheet from '@/vendors/xlsx'; import renderPdf from '@/vendors/pdf'; import renderImage from '@/vendors/image'; import renderText from '@/vendors/text'; import renderMp4 from '@/vendors/mp4'; // 假装构造一个vue的包装,让上层统一处理销毁和替换节点 const VueWrapper = el => ({ $el: el, $destroy() { // 什么也不需要 nothing to do }, }); const handlers = [ // 使用docxjs支持,目前效果最好的渲染器 { accepts: [ 'docx' ], handler: async (buffer, target) => { const docxOptions = Object.assign(defaultOptions, { debug: true, experimental: true, }); await renderAsync(buffer, target, null, docxOptions) return VueWrapper(target); } }, // 使用pptx2html,已通过默认值更替 { accepts: [ 'pptx' ], handler: async (buffer, target) => { await renderPptx(buffer, target, null); window.dispatchEvent(new Event('resize')); return VueWrapper(target); }, }, // 使用sheetjs + handsontable,无样式 { accepts: [ 'xlsx' ], handler: async (buffer, target) => { return renderSheet(buffer, target); }, }, // 使用pdfjs,渲染pdf,效果最好 { accepts: [ 'pdf' ], handler: async (buffer, target) => { return renderPdf(buffer, target); } }, // 图片过滤器 { accepts: [ 'gif', 'jpg', 'jpeg', 'bmp', 'tiff', 'tif', 'png', 'svg' ], handler: async (buffer, target) => { return renderImage(buffer, target); } }, // 纯文本预览 { accepts: [ 'txt', 'json', 'js', 'css', 'java', 'py', 'html', 'jsx', 'ts', 'tsx', 'xml', 'md', 'log' ], handler: async (buffer, target) => { return renderText(buffer, target) }, }, // 视频预览,仅支持MP4 { accepts: [ 'mp4' ], handler: async (buffer, target) => { renderMp4(buffer, target) return VueWrapper(target); }, }, // 错误处理 { accepts: [ 'error' ], handler: async (buffer, target, type) => { target.innerHTML = `不支持.${type}格式的在线预览,请下载后预览或转换为支持的格式 支持docx, xlsx, pptx, pdf, 以及纯文本格式和各种图片格式的在线预览`; return VueWrapper(target); } } ] // 匹配 export default handlers.reduce((result, { accepts, handler }) => { accepts.forEach(type => result[type] = handler) return result; }, {});
ok,大功告成!😄
还好我们前期做足了工夫,一下子就运行起来了,但是很快就遇到了问题:
好不容易修改好了这些,终于跑起来了。大家可以在我的在线demo看到效果 file-viewerhttp://viewer.flyfish.group/
实现这个功能总体来说还是非常困难的,除了有很多坑,找到可用的开源组件也是耗费了我大量的精力。好在前期做的努力没有白费,成功上线了产品,也得到了领导的认可罒ω罒,嘿嘿。现在我把我的项目共享出来,我已经把源码上传了。本着对技术尊重的态度,大家帮忙打赏一两块钱就可以拿到完整的源码。
此外,我也会不断的优化更新,修改bug,提升性能,希望大家持续关注我,有人关注我就一定会一直努力的!谢谢大家!最后附上链接:
Web端文件预览,纯前端Vue实现的file-viewer,不需要后端,支持所有主流格式,附带接入文档和嵌入式引用demo-Web开发文档类资源-CSDN下载
本文提供了稳健的实现方案,以及全网资源对比整合,还提供了封装好的组件,想要源码可以微信搜索 Yous_Gift ,添加客服小姐姐详询。
最后的最后,希望大家写代码都能无bug!如果文章确实帮到了你,麻烦给个关注,谢谢!