纯前端文档预览,还要支持所有主流格式,有这一篇就足够了

写在前面

        纯前端的文档预览功能,是非常常见的需求,但就是这么简单的需求,难住了许多可爱的小伙伴们。别急,先访问一下解决方案,给你一个惊喜,再往下看:

文件在线预览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-MethodsGET

功能入口如下:

实现效果

word文档预览 

Excel文档预览 

 PPT文档预览

 PDF文档预览

Markdown预览

 图片预览

文本预览

视频预览

看完了之后,废话不多说,来给大家梳理梳理实现思路。

现存的方案和不足

笔者在接到这个功能需求后,对市面上目前的实现方案进行了归纳和梳理,不外乎就三种:

  1. PDF预览使用pdfjs,Office文档使用微软的提供的预览URL。该方案确实省事,而且效果是最好的,但是有个很大的问题,文件链接必须是公网链接,这对于在企业网或局域网部署的系统来说,基本上是不可行的方案,pass
  2. 使用Java后端统一转换为PDF,然后在前端预览。该方案兼容性较好,效果仅次于在线Office,但是对于服务器的压力比较大,在动辄要“高并发,高可用,高吞吐量”的互联网场景下总是不那么合适,基于OpenOffice的文件转换非常耗费IO,pass
  3. 客户端本地安装Office,利用浏览器的Office插件进行预览。这种实现方式对客户端要求较高,基本上不考虑,毕竟我们是web预览嘛,谁知道客户用的是啥浏览器,pass

意外的收获

        到此为止,所有的方案都被pass掉了,非常绝望。无果后,我搭上梯子,疯狂Google,终于找到了一个jquery的开源插件,叫做officeToHtml,出于对开源的尊重,这里提供一下人家的访问链接:OfficeJs | Demos

        这个开源项目非常好用,引用它的demo就能直接预览主流格式,但是它是基于JQuery的。事实上,当时我都已经通过这个方案实现了,结果我们领导说不是Vue,而且用的组件也太老了,强行pass掉了。现实总是残酷的,看着我头顶所剩不多的秀发,深深叹了口气,准备自己再次开整。

        有了国外大佬的思路提供,我的思路也渐渐清晰:

  1. 要解决这个问题,还是得用Vue实现
  2. 大佬的项目是jquery写的,我用Vue实现,也没说不让引用jQuery呀
  3. 分析一下大佬使用的开源组件,去GitHub上找最新的或者效果最好的,说不定有Vue版本呢
  4. 自己封装渲染入口,根据扩展名动态匹配渲染器,解析需要的格式。

        OK,思路清晰了,我们开始撸代码。

开始实现

       一、找替代框架

        大佬的框架已经老得不被待见了,大致整理后,笔者找到的最贴近且效果最好的框架都在下面的表里了:

文档格式        老的开源组件替代开源组件
word(docx)mammothdocx-preview(npm)

powerpoint(pptx)

pptxjs

pptxjs改造开发

excel(xlsx)sheetjs、handsontableexceljs(npm)、handsontable(npm)
pdf(pdf)pdfjspdfjs(npm)
图片jquery.verySimpleImageViewerv-viewer(npm)

        升级后的组件完全兼容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 是一些常用工具类,主要做二进制数据和字节码、字符串互转的。当然,文档渲染入口也在里面,我们后面说。

<template>
  <div :class="{hidden}">
    <div class="banner">
      <div class="container">
        <h1><a href="/">Vue在线文档查看器<input class="file-select" type="file" @change="handleChange"/></a></h1>
      </div>
    </div>
    <div class="container">
      <div v-show="loading" class="well loading">正在加载中,请耐心等待...</div>
      <div v-show="!loading" class="well" ref="output"></div>
    </div>
  </div>
</template>

<script>
import { getExtend, readBuffer, render } from '@/components/util';
import { parse } from 'qs';

/**
 * 支持嵌入式显示,基于postMessage支持跨域
 * 示例代码:
 *
 */
export default {
  name: 'HelloWorld',
  props: {
    msg: String
  },
  data() {
    return {
      // 加载状态跟踪
      loading: false,
      // 上个渲染实例
      last: null,
      // 隐藏头部,当基于消息机制渲染,将隐藏
      hidden: false,
    }
  },
  methods: {
    async handleChange(e) {
      this.loading = true;
      try {
        const [ file ] = e.target.files;
        const arrayBuffer = await readBuffer(file);
        this.loading = false
        this.last = await this.displayResult(arrayBuffer, file)
      } catch (e) {
        console.error(e)
      } finally {
        this.loading = false
      }
    },
    displayResult(buffer, file) {
      // 取得文件名
      const { name } = file;
      // 取得扩展名
      const extend = getExtend(name);
      // 输出目的地
      const { output } = this.$refs;
      // 生成新的dom
      const node = document.createElement('div');
      // 添加孩子,防止vue实例替换dom元素
      if (this.last) {
        output.removeChild(this.last.$el);
        this.last.$destroy();
      }
      const child = output.appendChild(node);
      // 调用渲染方法进行渲染
      return new Promise((resolve, reject) => render(buffer, extend, child)
          .then(resolve).catch(reject));
    }
  }
}
</script>

<style scoped>
.banner {
  overflow: auto;
  text-align: center;
  background-color: #12b6ff;
  color: #fff;
}

.hidden .banner {
  display: none;
}

.hidden .well {
  height: calc(100vh - 12px);
}

.file-select {
  position: absolute;
  left: 5%;
  top: 17px;
  margin-left: 20px;
}

.banner a {
  color: #fff;
}

.banner h1 {
  font-size: 20px;
  line-height: 2;
  margin: 0.5em 0;
}

.well {
  display: block;
  background-color: #f2f2f2;
  border: 1px solid #ccc;
  margin: 5px;
  width: calc(100% - 12px);
  height: calc(100vh - 73px);
  overflow: auto;
}

.loading {
  text-align: center;
  padding-top: 50px;
}

.messages .warning {
  color: #cc6600;
}
</style>

        三、实现渲染入口

           写好容器后,下一步就是重头戏,笔者这里使用匹配模式简单实现了一个渲染入口,代码如下:

// 导入渲染器
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 = `<div style="text-align: center; margin-top: 80px">不支持.${type}格式的在线预览,请下载后预览或转换为支持的格式</div>
<div style="text-align: center">支持docx, xlsx, pptx, pdf, 以及纯文本格式和各种图片格式的在线预览</div>`;
      return VueWrapper(target);
    }
  }
]

// 匹配
export default handlers.reduce((result, { accepts, handler }) => {
  accepts.forEach(type => result[type] = handler)
  return result;
}, {});

          ok,大功告成!😄

       四、运行调试

        还好我们前期做足了工夫,一下子就运行起来了,但是很快就遇到了问题:

  1. pptxjs的npm版本无法使用,有很多bug,只能下载源码自己改bug,作者已经不维护了
  2. exceljs解析sheet的时候有超级多坑,踩到吐🤮
  3. 性能问题,遇到几十兆的pdf,打开超级慢,页面会假死(等待一会就好了)。这个也需要进一步优化

        好不容易修改好了这些,终于跑起来了。大家可以在我的在线demo看到效果 file-viewericon-default.png?t=N7T8http://viewer.flyfish.group/

        五、总结一下

          实现这个功能总体来说还是非常困难的,除了有很多坑,找到可用的开源组件也是耗费了我大量的精力。好在前期做的努力没有白费,成功上线了产品,也得到了领导的认可罒ω罒,嘿嘿。现在我把我的项目共享出来,我已经把源码上传了。本着对技术尊重的态度,大家帮忙打赏一两块钱就可以拿到完整的源码。

        此外,我也会不断的优化更新,修改bug,提升性能,希望大家持续关注我,有人关注我就一定会一直努力的!谢谢大家!最后附上链接:

Web端文件预览,纯前端Vue实现的file-viewer,不需要后端,支持所有主流格式,附带接入文档和嵌入式引用demo-Web开发文档类资源-CSDN下载

        本文提供了稳健的实现方案,以及全网资源对比整合,还提供了封装好的组件,想要源码可以微信搜索 Yous_Gift ,添加客服小姐姐详询。

        最后的最后,希望大家写代码都能无bug!如果文章确实帮到了你,麻烦给个关注,谢谢!

  • 105
    点赞
  • 245
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 266
    评论
### 回答1: docxpreview是一种可以在前端实现的文档预览工具,可以方便地预览和浏览.docx格式文档。实现docxpreview前端主要包括以下几个步骤。 首先,前端需要通过接口或后端提供的服务获取.docx文件的二进制数据或URL。可以使用AJAX技术进行异步请求,并将获取到的文件数据存储在前端。 接下来,前端需要将获取到的.docx文件进行解析,提取其中的文本和格式信息,并根据需要进行样式的调整和布局的优化。可以使用第三方的JavaScript库,如JSZip和officegen来帮助解析.docx文件。 然后,前端需要将解析后的文本和格式信息渲染到HTML页面上,以便用户可以直接在前端页面上进行预览。可以使用HTML和CSS来创建页面结构和样式,并将解析后的文本插入到相应的元素中。 在渲染过程中,前端还可以添加一些交互功能,例如放大缩小、翻页和搜索等,以提升用户体验。可以使用JavaScript来实现这些功能,并与HTML和CSS进行交互。 最后,前端需要进行一些错误处理和异常处理,确保在预览过程中出现错误时能够及时提示用户或提供相关的错误信息。 综上所述,docxpreview文档预览前端实现主要包括获取.docx文件数据,解析文本和格式信息,渲染到HTML页面,并添加交互功能和错误处理等步骤。通过这些步骤可以实现一个简单但功能完善的.docx文档预览前端。 ### 回答2: docxpreview文档预览是一种前端实现的技术,它通过使用一些特定的技术和工具,在网页上实现对docx文档预览功能。 首先,实现docx文档预览的前提是需要将docx文档转换成可被网页展示的格式。这可以通过一些在线的或者本地的转换工具来实现,比如使用Microsoft Office自带的Office Online服务,或者使用一些第三方的开源库,如Apache POI等。这些工具可以将docx文档转换为HTML、PDF或者其他网页可以读取和展示的格式。 然后,在前端页面上实现docx文档预览功能需要引入一些前端技术和工具。常见的有使用HTML、CSS和JavaScript来实现网页的布局和交互效果。我们可以在网页上嵌入一个可以显示HTML或者PDF内容的iframe,通过将转换后的文档内容加入到该iframe中,就可以在网页上实现对docx文档预览功能。 另外,为了提升用户体验和功能完善,我们可以引入一些额外的功能。比如,可以添加页面导航按钮,让用户可以在预览文档时进行翻页操作;也可以添加搜索功能,让用户可以根据关键词在文档中进行搜索;还可以添加缩放功能,让用户可以根据自己的需求对文档进行放大或缩小等等。 综上所述,docxpreview文档预览前端实现需要将docx文档转换为可被网页展示的格式,然后在前端页面上通过HTML、CSS和JavaScript等技术进行实现。同时,为了提升用户体验和功能完善,可以添加一些额外的功能。 ### 回答3: docxpreview文档预览前端实现是指通过前端技术实现对docx格式文档进行预览的功能。实现该功能需要以下步骤: 1. 获取docx文件:用户在前端页面上选择docx文件,通过文件上传功能将文件传输到后台服务器。 2. 后台处理:后台服务器接收到传输的docx文件后,需要对文件进行解析和处理。可以使用开源的文档处理库,如Apache POI或Aspose Words等,对docx文件进行解析,提取其中的内容和格式信息。 3. 前端渲染:后台处理完成后,将提取的内容和格式信息传输到前端前端可以使用HTML和CSS技术对提取的内容进行渲染和展示。可以将文本内容显示为段落、标题、表格等形式,并自定义样式,如字体、大小、颜色等。 4. 图片预览:如果docx文件中包含图片,前端需要将这些图片进行处理并显示。可以通过解析docx文件中的图片路径,并将图片转换成base64编码格式,以便在前端页面上显示。 5. 页面交互:为了提升用户体验,可以在前端页面上添加一些交互功能。比如,支持缩放、滚动、跳转页等操作,让用户能够更方便地浏览和阅读文档。 总之,实现docxpreview文档预览前端功能,需要通过后台解析和处理docx文件,并将提取的内容和格式信息传输到前端进行渲染和展示。同时,还需要处理文档中的图片,并提供一些交互功能,以提升用户体验。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 266
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小爬的老粉丝

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值