vue3+vite使用pdf.js

记录一下vue3+vite使用pdf.js的经验和遇到的坑......

1、安装pdf.js

npm install pdfjs-dist

2、使用案例如下:

(1) 创建pdfService.js

import { getDocument } from 'pdfjs-dist';
const pdfService = {
    async loadPdf(url) {
        return await getDocument(url).promise;
    },
    async getPage(pdf, pageNum) {
        return await pdf.getPage(pageNum);
    }, 
};
export default pdfService;

(2) 组件页面代码:

<template>
  <div id="document">
    <div class="documentFlex document-left">
      <h3>浙江自然:海外基地增长可观</h3>
      <div class="date">2024-11-12 19:11</div>
      <div class="canvas">
        <canvas
          ref="canvas"
          :id="`pdfCanvas${page}`"
          v-for="page in totalPages"
          :key="page"
        ></canvas>
      </div>
    </div>
  
  </div>
</template>
<script lang="ts">
import {
  defineComponent,
  nextTick,
  onMounted,
  reactive,
  ref,
  toRefs,
} from "vue";
import pdfService from "./pdfService";
export default defineComponent({
  setup(props) {
    const canvas = ref(null);
    const state = reactive({
      activeName: "1",
      pdf: <any>null,
      currentPage: 1,
      totalPages: 0,
    });
    onMounted(async () => {
        //1.如果后台返回具体的pdf地址http则使用一下方法
      state.pdf = await pdfService.loadPdf(
        "https://path/file"
      ); //从后台拿到pdf地址
      state.totalPages = state.pdf.numPages;
      nextTick(() => {
        renderPage(state.currentPage); // 表示渲染第 1 页
      });
        //2.如果后台返回的是pdf文件乱码则需要利用blob转化(res是从后台获取的乱码)
          // let blob = new Blob([res], {
          //   type: "application/pdf",
          // });
          // const pdfUrl = URL.createObjectURL(blob);
          // // 加载 PDF 文件
          // pdfService.loadPdf(pdfUrl).then((res) => {
          //   state.pdf = res;
          //   state.totalPages = res.numPages;
          //   nextTick(() => {
          //     renderPage(state.currentPage); // 表示渲染第 1 页
          //   });
          // });
    });
    const renderPage = async (pageNum) => {
      const page = await pdfService.getPage(state.pdf, pageNum);
      let canvas: any = document.getElementById(`pdfCanvas${pageNum}`);
      let ctx = canvas.getContext("2d");
      let dpr = window.devicePixelRatio || 1;
      let bsr =
        ctx.webkitBackingStorePixelRatio ||
        ctx.mozBackingStorePixelRatio ||
        ctx.msBackingStorePixelRatio ||
        ctx.oBackingStorePixelRatio ||
        ctx.backingStorePixelRatio ||
        1;
      let ratio = dpr / bsr;
      let viewport = page.getViewport({ scale: 1 });
      canvas.width = viewport.width * ratio;
      canvas.height = viewport.height * ratio;
      // canvas.style.width = "100%";
      // canvas.style.height = "100%";
      ctx.setTransform(ratio, 0, 0, ratio, 0, 0);
      // 将 PDF 页面渲染到 canvas 上下文中
      let renderContext = {
        canvasContext: ctx,
        viewport: viewport,
      };
      page.render(renderContext);
      if (state.totalPages > pageNum) {
        renderPage(pageNum + 1);
      }
    };

    
    return {
      canvas,
      ...toRefs(state),
    };
  },
});
</script>

<style scoped lang="scss">
#document {
  padding: 20px;
  display: flex;
  width: 100%;
  background: #fff;
  justify-content: space-between;
  .document-left {
    text-align: center;
    display: flex;
    flex-direction: column;
    .date {
      color: rgba(51, 51, 51, 0.65);
      font-size: 14px;
    }
    .canvas {
      overflow: auto;
      margin-top: 20px;
    }
  }
 
}
</style>

3.踩得坑:

(1)

莫名其妙报了个 getPage的错误,上网找了一下说是和vue3的proxy有关,pdfjs-dist拦截校验的时候,应该是需要一个原始对象,但通过vue3获取到的是一个proxy响应式的对象,这里使用toRaw()将proxy转化为原始对象就可以了修改pdfService.js:

import { getDocument } from 'pdfjs-dist';
import * as pdfjsLib from "pdfjs-dist/build/pdf.worker.min.mjs";
import { toRaw } from 'vue';//使用toRaw

const pdfService = {
    async loadPdf(url) {
        return await getDocument(url).promise;
    },
    async getPage(pdf, pageNum) {
        return await toRaw(pdf).getPage(pageNum);//使用toRaw
    }, 
};
export default pdfService;

(2)

处理好上面之后 对于最新的浏览器版本是没有问题的,但是后面经过测试发现低版本浏览器比如谷歌可能会出现下面报错:

在Vue 3中,Promise.withResolvers 方法不存在,通常是因为在代码中使用的环境不支持Promise.withResolvers ,或者使用的 pdfjs 库和浏览器环境不兼容。 Promise.withResolvers 是 ES2023 引入的一个新特性,允许你同时创建一个 Promise 对象和它的 resolve 和 reject 函数。如果浏览器版本不支持这个特性,就会出现这个错误。

解决方案:

(1)安装core-js:

npm install core-js

如果有用到async/await,需要安装regenerator-runtime:

npm install --save regenerator-runtime

Vue 3 是基于 ES6+ 特性的,因此如果你想在你的项目中引入 core-js polyfill,你需要配置babel 或者通过 Vite 配置来确保它被正确引入。

(2)修改 vite.config.js 配置:

Vite 默认使用 esbuild 来处理代码。为了支持 core-js ,你需要配置 babel 来包含 polyfills
首先,安装 @vitejs/plugin-vue 插件(如果还没有安装的话):
npm install @vitejs/plugin-vue
接着,在你的 vite.config.js 文件中进行如下配置:
import { defineConfig } from 'vite';
import vue from '@vitejs/plugin-vue';

export default defineConfig({
    plugins: [vue()],
    define: {
        'process.env': {},
    },
    build: {
        target: 'esnext', // 根据需要修改目标版本
    },
});

(3)在入口文件main.js 或 main.ts 中引入 core-js 和regenerator-runtime:

import 'core-js/stable'; // 引入所有稳定版本的 polyfills
import 'regenerator-runtime/runtime'; // 如果你使用了 async/await,可能需要这个

这样就兼容了低版本的浏览器。

Vue 3结合Vite可以构建出高性能的前端应用。实现PDF文件预览,可以通过以下几种方法: 1. 使用第三方库插件:比如`pdfjs-dist`或者`react-pdf`等,这些库可以帮助我们解析和渲染PDF文件。在Vue 3项目中,你可以通过npm或yarn安装这些库,然后在组件中引入并使用它们提供的组件或API进行PDF的加载和显示。 2. 使用`<iframe>`标签嵌入:如果你的PDF文件可以在线访问,可以直接使用`<iframe>`标签嵌入PDF文件的URL。这样用户可以直接在浏览器中预览PDF文件。但这种方法的缺点是不能进行交互操作,比如缩放、翻页等。 3. 使用Web组件库:一些Web组件库,如`pdf-viewer`,提供了一个Vue组件,可以直接在Vue项目中使用,从而实现PDF文件的预览。使用此类组件时,只需要按照组件文档安装并按照示例代码操作即可。 具体实现步骤如下: 1. 安装`pdfjs-dist`: ```bash npm install pdfjs-dist ``` 2.Vue组件中使用`pdfjs-dist`来加载PDF文件,并渲染每一页: ```javascript <template> <div> <!-- PDF 渲染区域 --> <div id="pdf-container"></div> </div> </template> <script> import { getDocument } from &#39;pdfjs-dist/legacy/build/pdf&#39;; export default { name: &#39;PdfViewer&#39;, mounted() { this.loadPdf(); }, methods: { async loadPdf() { const pdfUrl = &#39;path/to/your/pdf/file.pdf&#39;; const loadingTask = getDocument(pdfUrl); try { const pdf = await loadingTask.promise; this.renderPages(pdf); } catch (error) { console.error(&#39;Error loading PDF&#39;, error); } }, renderPages(pdf) { const container = document.getElementById(&#39;pdf-container&#39;); for (let i = 1; i <= pdf.numPages; i++) { pdf.getPage(i).then(page => { // 创建canvas元素来渲染页面 const canvas = document.createElement(&#39;canvas&#39;); const context = canvas.getContext(&#39;2d&#39;); const viewport = page.getViewport({ scale: 1.5 }); canvas.height = viewport.height; canvas.width = viewport.width; const renderContext = { canvasContext: context, viewport: viewport }; page.render(renderContext).promise.then(() => { container.appendChild(canvas); }); }); } } } }; </script> ``` 在上面的代码中,我们使用了`pdfjs-dist`库来加载和渲染PDF页面。注意,这只是一个基本的实现,实际应用中可能需要更多的功能,比如页面导航、缩放、下载等。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值