前端pdf预览方案

前端pdf预览方案

pdf预览一般不需要前端生成pdf文件,pdf文件一般是通过接口,获取pdf文件【responseType:'blob',】或二进制文件流【responseType: 'arraybuffer',】或者已有的pdf文件。

前端PDF预览通常是通过读取现有的PDF文件,并使用Canvas或SVG等元素在网页上展示PDF内容

前端预览PDF的最好方式还是让服务器端处理,不光对于前端,也包括后端,这应该是最方便的也是最不易出现问题的方法。

通过接口直接获取Canvas文件流,或svg代码或者文件流。避免了前端做pdf读取操作【前端pdf预览插件大多都很老了,各有隐患,而且pdf读取肯定会慢】;同时也避免了可能出现的不同设备出现的兼容性问题【pc,安卓,ios】。

如果一定要前端处理pdf预览,下面方案仅供参考:

使用 iframe、embed、新窗口打开【看天吃饭,基本不建议】
复制代码
<embed src="https://demo/path.pdf">

<iframe src="https://demo/path.pdf"></iframe>

优点:简单,支持大部分 PC 浏览器(IE 不支持)。跨域资源同样可以(无需 cors)

缺点:不支持移动端浏览器,不支持 IE 等低版本浏览器。样式无法自定义。

pdfjs插件【https://www.npmjs.com/package/pdfjs-dist】

pdfjs插件是最流行的、PDF预览、JavaScript库

PDF.js作为Mozilla开发的一个JavaScript库,旨在提供一个纯JavaScript实现的PDF文件解析和渲染解决方案,使用户能在浏览器环境中无缝地查看PDF文档,而无需依赖任何插件。

PDF.js使用现代Web技术,包括WebGL(用于高级图形渲染)和HTML5

Canvas(用于基本绘图操作),来解析PDF文件的内容,并将其转换为可在浏览器中展示的元素。它提供了丰富的API和配置选项,允许开发者根据需求调整界面样式和功能。此外,PDF.js还支持缩放、旋转、拖动等PDF操作,以及导出为图片和提取文字等功能。

缺点:PDF.js是支持iOS预览的,但可能需要注意一些版本兼容性和实现方式的问题。

pdf.js在ios系统里和Safari浏览器可能出现的兼容性问题
  1. Safari版本问题 :某些旧版本的Safari浏览器可能不支持pdf.js所需的一些JavaScript特性或API,导致无法正常使用。例如,早期版本的Safari不支持私有类字段(这是ES2022引入的特性),而某些版本的pdf.js可能使用了这一特性。
  2. 代码实现问题 :如果pdf.js的代码实现与Safari浏览器的某些特性存在冲突,也可能导致无法正常使用。例如,pdf.js在Safari中可能无法正确解析或渲染PDF文件,或者出现空白页面等问题。
二、解决方案
  1. 升级Safari浏览器 :确保你的Safari浏览器是最新版本,以便支持pdf.js所需的JavaScript特性和API。
  2. 使用兼容版本的pdf.js :如果你正在使用的pdf.js版本与Safari存在兼容性问题,可以尝试使用旧版本的pdf.js,这些版本可能更兼容Safari浏览器。例如,有用户报告说将pdf-dist库降级为v2.4.456可以解决在Safari中的兼容性问题。
  3. 调整代码实现 :如果你有能力修改pdf.js的代码,可以尝试调整代码实现以兼容Safari浏览器。例如,避免使用Safari不支持的JavaScript特性或API,或者添加针对Safari的特定处理逻辑。
  4. 使用第三方库或工具 :如果以上方法都无法解决问题,你可以考虑使用其他第三方库或工具来在Safari中预览PDF文件。这些库或工具可能已经针对Safari浏览器进行了优化和测试,具有更好的兼容性和稳定性。
pdfjs的使用方式
javascript 复制代码
// pdf有两种使用方式:
第一种是pdfjs-view(pdfjs-view-es5)分为两个版本/web/viewer-1.html 和 /legacy/web/viewer.html 。legacy 支持低版本浏览器,使用 es5 编写
const res = await downloadPdf({
      date: reportDate.value,
    })
    const resUrl = URL.createObjectURL(res);
    window.open(`./pdf/web/viewer.html?file=${resUrl}`);

第二种是通过js实现:
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>testDemo</title>
  <script src="./pdf/build/pdf.js"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/axios/1.7.7/axios.min.js"></script>
  <style>
    .pdf {
      display: flex;
      align-items: center;
      justify-content: center;
      height: 100vh;
      background-color: #f4f4f9;
      margin: 0;
      padding: 0;
    }

    #preViewPdf {
      width: 100%;
      height: 100vh;
      background: white;
      box-shadow: 0px 4px 8px rgba(0, 0, 0, 0.2);
      border-radius: 8px;
      overflow-y: auto;
      position: relative;
    }

    #loading {
      position: absolute;
      color: #555;
      font-size: 1.2em;
      top: 50%;
      left: 50%;
      transform: translate(-50%, -50%);
    }

    .pdf-page {
      display: flex;
      justify-content: center;
      margin-bottom: 10px;
    }

    canvas {
      max-width: 100%;
      height: auto;
    }
  </style>
</head>

<body>
  <div class="pdf">
    <div id="preViewPdf">
      <div id="loading">Loading1114...</div>
    </div>
  </div>
</body>
<script>
  window.onload = async function () {
    const el = document.getElementById('preViewPdf');
    const loadingText = document.getElementById("loading");
    const res = await axios({
      url: '/demo.pdf',
      method: "get",
      // responseType: 'arraybuffer',
      responseType: 'blob',
    })
    const resUrl = URL.createObjectURL(res.data);
    // 加载 pdf 资源
    let loadingTask = pdfjsLib.getDocument(resUrl)
    // PDF 加载完成的回调。
    loadingTask.promise.then(function (pdf) {
      pdf.getPage(1).then(function (page) {
        var viewport = page.getViewport({
          scale: 1,
        });
        // var scale = (500 / viewport.width).toFixed(2)
        // console.log('日志:', scale);
        // viewport = page.getViewport({
        //   scale: scale
        // });
        var canvas = document.createElement('canvas');
        el.appendChild(canvas)
        var context = canvas.getContext('2d');
        canvas.height = viewport.height;
        canvas.width = viewport.width;

        // 创建了一个canvas画板用来存放
        var renderContext = {
          canvasContext: context,
          viewport: viewport
        };
        loadingText.style.display = 'none'
        page.render(renderContext);
      });
    }, function (reason) {
      console.error(reason)
    })
  }
</script>

</html>
另一个插件pdfH5【https://www.npmjs.com/package/pdfh5】

注意:

  1. 这是一个很老的插件,可能这个差价的部分依赖插件已经停止维护了;

  2. 如果有报错,请复制example运行,然后对照相关文件,以及package.json,缺什么补什么

  3. 如果有某些字体显示不了,那可能是pdf.js缺少相关字库解析,可以尝试更改cMapUrl,建议去官方地址找版本

  4. 如果IOS下pdf显示不了,安卓却可以,可能是pdf精度过高导致,Safari浏览器canvas渲染绘制图片宽高不能超过16777216,超过会不显示

    如果可以用,这个插件使用还是很方便的,但是如果有问题,还是换回pdf.js吧

    示例:
    <template>

    </template> <script> import Pdfh5 from "pdfh5"; export default { name: 'App', data() { return { pdfh5: null }; }, mounted() { //实例化 this.pdfh5 = new Pdfh5("#demo", { pdfurl: "../../static/test.pdf", // cMapUrl:"https://unpkg.com/pdfjs-dist@3.8.162/cmaps/", // responseType: "blob" // blob arraybuffer }); //监听完成事件 this.pdfh5.on("complete", function (status, msg, time) { console.log("状态:" + status + ",信息:" + msg + ",耗时:" + time + "毫秒,总页数:" + this.totalNum) //禁止手势缩放 this.pdfh5.zoomEnable(false); }) } } </script> <style> @import "pdfh5/css/pdfh5.css"; *{ padding: 0; margin: 0; } html,body,#app { width: 100%; height: 100%; } </style>
下载 PDF【一个简单的办法,特殊情况可用】
  1. 下载头
  2. 直接打开
    1. 如果浏览器不支持解析 PDF 那么可以触发下载。
    2. 如果浏览器支持解析 PDF,那么会变成预览。
    3. 这个时候我们可以给 a 标签加上 download 来触发下载。(需要同域)
相关推荐
foxhuli229几秒前
禁止ifrmare标签上的文件,实现自动下载功能,并且隐藏工具栏
前端
青皮桔32 分钟前
CSS实现百分比水柱图
前端·css
影子信息37 分钟前
vue 前端动态导入文件 import.meta.glob
前端·javascript·vue.js
guygg8837 分钟前
深入理解SpringMVC DispatcherServlet源码及全流程原理
状态模式
青阳流月38 分钟前
1.vue权衡的艺术
前端·vue.js·开源
样子201842 分钟前
Vue3 之dialog弹框简单制作
前端·javascript·vue.js·前端框架·ecmascript
kevin_水滴石穿43 分钟前
Vue 中报错 TypeError: crypto$2.getRandomValues is not a function
前端·javascript·vue.js
孤水寒月2 小时前
给自己网站增加一个免费的AI助手,纯HTML
前端·人工智能·html
CoderLiu2 小时前
用这个MCP,只给大模型一个figma链接就能直接导出图片,还能自动压缩上传?
前端·llm·mcp
伍哥的传说2 小时前
鸿蒙系统(HarmonyOS)应用开发之实现电子签名效果
开发语言·前端·华为·harmonyos·鸿蒙·鸿蒙系统