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

news2025/2/26 19:36:50

写在前面

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

文件在线预览DEMO

服务器文件预览DEMO

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文档预览

 图片预览

文本预览

 视频预览

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

现存的方案和不足

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

  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-viewerhttp://viewer.flyfish.group/

        五、总结一下

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

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

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

        

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/405336.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【计算机网络】Web服务器的配置

目录 课题描述 需求分析 2.1 WEB服务器基本构架 2.1.1 WEB服务器和浏览器 2.2 HTTP协议 2.2.1 HTTP简介 2.2.2 HTTP工作原理 2.3 FTP协议 2.3.1 FTP简介 2.3.2 FTP工作原理 2.4 ISS服务作用 概要设计 3.1 ISS服务器的安装与配置 3.2 详细设计 结果分析 4.1 We…

JS实现轮播图(一看就懂逻辑清晰)

轮播图有很多种实现方法&#xff0c;这是其中一种最清晰的方法。思路很清晰&#xff0c;代码很简单&#xff0c;欢迎大佬多指教。 先来看下效果图&#xff0c;嫌麻烦就不用具体图片来实现了&#xff0c;主要是理清思路。&#xff08;自动轮播&#xff0c;左右按钮切换图片&…

Vue首屏加载过慢出现白屏的六种优化方案

公司业务展示官网开发&#xff0c;构建版本后在测试环境下&#xff0c;发下首屏加载损耗高达几十秒&#xff08;服务器在国外&#xff0c;所以也导致加载时间变长&#xff09;&#xff0c;于是采用了以下方法来达到提速目的。 1. 采用懒加载的方式 路由懒加载和组件懒加载&a…

【Node.js】初识Node.js

系列文章目录 文章目录系列文章目录一、什么是 Node.js二、下载和安装 Node.js1、普通方式2、使用 nvm 安装三、Node.js 和 JavaScript 的区别1、ECMScript2、JavaScript3、node.js四、commonjs1、什么是 commonjs2、安装 lodash五、debugger六、server 开发和前端开发的区别一…

Vue3实战教程(快速入门)

Vue3实战教程&#xff08;快速入门&#xff09;前言1.搭建脚手架1.1 创建项目1.2 清除多余文件&#xff0c;创建干净项目1.3 创建登录页面2.创建404页面&#xff08;引入sass&#xff09;2.1 引入sass2.2 创建404页面3.构建登录注册页面&#xff08;引入element-plus&#xff0…

VSCode安装配置使用教程(最新版超详细保姆级含插件)一文就够了

前言 Visual Studio Code 是一个轻量级功能强大的源代码编辑器&#xff0c;支持语法高亮、代码自动补全&#xff08;又称 IntelliSense&#xff09;、代码重构、查看定义功能&#xff0c;并且内置了命令行工具和 Git 版本控制系统。适用于 Windows、macOS 和 Linux。它内置了对…

如何解决Vue3没有代码提示问题?

在上一篇笔记中提到了Vue3viteTs写代码过程中&#xff0c;出现的代码自动补全失效功能&#xff0c;今天来谈谈如何解决这个问题。 首先&#xff0c;我们已经很明确的就是安装了volar插件之后&#xff0c;HTML标签片段补全已经失效&#xff0c;即在template中书写HTML标签时&am…

IDEA2022版本创建maven web项目(两种方式)最全图文教学

IDEA2022版本创建maven web项目 问题发生时间&#xff1a;2022.1.3 问题描述&#xff1a;新版本的idea2022很多人不解的地方就是创建项目之后没有Web文件夹&#xff0c;这让项目创建的过程中产生了困难 提示&#xff1a;环境搭建的过程中请注意细节问题&#xff0c;避免粗心大…

Vue开发实例(20)之实现登录功能

引言 Vue是现在前端最流行的框架之一&#xff0c;作为前端开发人员应该要熟练的掌握它&#xff0c;如果你是打算学习Vue的开发流程&#xff0c;那么来吧&#xff0c;明哥带你快速上手、带你飞&#xff01; 即使你并非前端开发人员&#xff0c;对前端的开发流程进行一定的了解也…

微信小程序简洁登录页面(附源码)

微信小程序简洁登录页面&#xff08;附源码&#xff09; 文章目录微信小程序简洁登录页面&#xff08;附源码&#xff09;1. 群聊&#xff08;开源项目以及技术交流&#xff09;2.看效果3.用户不存在4.上代码4.1login.wxml4.2login.css4.3login.js5.总结1. 群聊&#xff08;开源…

手把手教你用vue + node 作后端连接数据库

教程的顺序&#xff1a; 1、编写node服务器 2、用node连接数据库 3、编写前端页面 4、前后端交互 ok&#xff0c;让我们开始吧 1、编写node服务器 先下载几个依赖包 express&#xff08;用于网络连接&#xff09; npm i express --save cors&#xff08;用于处理跨域…

IDEA 2022专业版创建Java Web项目(保姆式小白讲义,强烈建议入手!)

这里先给出IDEA专业版的下载链接&#xff0c;没有下载的小伙伴&#xff0c;请先下载哦&#xff01;&#xff08;选择左边的Ultimate&#xff09; 目录 1.新建Java Class 2.添加框架 3. 配置Maven 4.配置项目结构 5.配置tomcat 本文致力于2022.3IDEA 专业版创建Java Web项目小白…

JS中的this指向

this的概念&#xff1a; 在js中&#xff0c;this的意思为“这个;当前”&#xff0c;是一个指针型变量&#xff0c;它动态指向当前函数的运行环境。 在不同的场景中调用同一个函数&#xff0c;this的指向也可能会发生变化&#xff0c;但是它永远指向其所在函数的真实调用者&…

如何在uniapp中优雅地使用WebView

这里给大家分享我在网上总结出来的一些知识&#xff0c;希望对大家有所帮助 从webview页面传值到uniapp中 官方文档已经很详细了,这里给大家上我的实战代码&#xff0c;首先在webview页面中引入相关依赖&#xff1a; <!-- uniapp各平台依赖 --> <script type"tex…

用uniapp实现微信小程序的电子签名效果

✅作者简介&#xff1a;大家好我是瓜子三百克&#xff0c;励志成为全栈工程师的一枚程序猿&#xff0c;也是喜欢在学习和开发中记录笔记的小白博主&#xff01; &#x1f4c3;个人主页&#xff1a;瓜子三百克的主页 &#x1f525;系列专栏&#xff1a;uniapp前端 &#x1f496;…

vue项目实战-电商后台管理系统

项目简介&#xff1a; 该项目为电商后台的管理系统。设计了登录页面。 管理人员需要通过输入正确的用户名和密码才能登录。登陆成功之后进入管理页面&#xff1a; 管理页面由五个子模块组成&#xff1a;用户管理&#xff0c;权限管理&#xff0c;商品管理&#xff0c;订单管理…

ChatGPT对话数据备份

ChatGPT对话数据备份 文章目录ChatGPT对话数据备份1. 背景2. 其他&#xff08;失败的&#xff09;方法2.1 右键另存为2.2 直接copy html代码3. 编写Javascript脚本3.1 思路过程3.2 安装教程3.3 使用说明3.4 最终效果1. 背景 之前在ChatGPT更新时有好几天都无法查看过往对话&am…

webpack 面试题整理

文章目录webpack 面试题整理谈谈你对Webpack的理解Webpack的打包过程/打包原理/构建流程&#xff1f;Webpack中loader的作用/ loader是什么&#xff1f;常见的loader有哪些&#xff1f;Plugin有什么作用&#xff1f;/Plugin是什么常见的Plugin有哪些Webpack 插件的执行顺序&…

15套前端经典实战项目大合集,小白练手必备实战项目

15套前端经典实战项目大合集&#xff0c;悄悄练习&#xff0c;你会惊艳所有人。 今日我以内卷为荣&#xff0c;明日内卷以我为荣&#xff0c;不管学习哪门语言都要做出实际的东西来&#xff0c;这个实际的东西就是项目。 这里整理了15前端经典实战项目&#xff0c;每套都有完…

nodejs高版本降为低版本方案

1.首先通过控制面板应用卸载当前环境下的Node.js相关安装&#xff0c;并清理磁盘残存的文件夹等文件 2.下载nvm来管理node版本 官网&#xff1a;https://github.com/coreybutler/nvm-windows/releases 说在前面&#xff0c;贴一个error C:\Windows\system32>nvm use 12.10.…