在 Vue3 TS 项目中 渲染 base64 格式的 pdf文件

333 阅读1分钟

前言:在项目中遇到了一个后端给过来的base64 格式的pdf文件,要求前端在h5端预览

踩坑方案一:只能支持web浏览器,不能在手机的壳子中展示

上代码:

  const base64Data = '你的数据base64编码';
  const byteCharacters = atob(base64Data);
  const byteNumbers = new Array(byteCharacters.length);
  for (let i = 0; i < byteCharacters.length; i++) {
    byteNumbers[i] = byteCharacters.charCodeAt(i);
  }
  const byteArray = new Uint8Array(byteNumbers);
  const blob = new Blob([byteArray], { type: 'application/pdf' });
  const fileUrl = URL.createObjectURL(blob);
<template>
    <iframe src={fileUrl} width="100%" height="500px"></iframe>
<template/>

最终解决方案 : 使用 ddfjs 插件

  1. 安装 pdfjs yarn add pdfjs-dist
  2. 使用 新建一个 PdfView.vue 组件
<script lang="ts">
import { defineComponent, ref, onMounted } from 'vue'
import * as pdfjsLib from 'pdfjs-dist'
/**
 *  这里要注意 一定要 将 node_modules/pdfjs-dist/build/pdf.worker.min.mjs 
 * 复制一份到public/pdf.worker.min.mjs
 */
pdfjsLib.GlobalWorkerOptions.workerSrc =
  '/pdf.worker.min.mjs'

export default defineComponent({
  name: 'PdfViewer',
  props: {
    base64Pdf: {
      type: String,
      required: true
    }
  },
  setup(props) {
    const pdfContainer = ref<HTMLDivElement | null>(null)

    onMounted(async () => {
      if (pdfContainer.value && props.base64Pdf) {
        try {
          const loadingTask = pdfjsLib.getDocument({ data: atob(props.base64Pdf) })
          const pdfDocument = await loadingTask.promise

          for (let pageNum = 1; pageNum <= pdfDocument.numPages; pageNum++) {
            const page = await pdfDocument.getPage(pageNum)
            const viewport = page.getViewport({ scale: 1.5 })
            const canvas = document.createElement('canvas')
            const context = canvas.getContext('2d')

            if (context) {
              canvas.height = viewport.height
              canvas.width = viewport.width
              await page.render({ canvasContext: context, viewport }).promise
              pdfContainer.value.appendChild(canvas)
            }
          }
        } catch (error) {
          console.error('Error rendering PDF:', error)
        }
      }
    })

    return { pdfContainer }
  }
})
</script>

<template>
  <div ref="pdfContainer" class="pdf-container"></div>
</template>

<style scoped>
.pdf-container {
  display: flex;
  flex-direction: column;
  gap: 16px;
}
canvas {
  border: 1px solid #ddd;
}
</style>

  1. 使用组件
<script setup lang="ts">
// demoData 为base64 string
import { demoData } from './components/data'
import PdfViewer from './components/pdfView.vue'
</script>

<template>
  <div class="pdf -page">
    <PdfViewer :base64Pdf="demoData" />
  </div>
</template>

<style lang="scss" scoped></style>