Vue3实现PDF文件解析与预览的完整实践

 更新时间:2025年06月17日 09:10:27   作者:黑土豆  
在实际的前端开发中,经常会碰到需要在线预览PDF文件的场景,比如后台管理系统查看合同、教育平台展示试卷、审批系统预览发票等等,所以本文给大家介绍了Vue3实现PDF文件解析与预览的完整实践,需要的朋友可以参考下

前言

在实际的前端开发中,经常会碰到需要在线预览PDF文件的场景,比如后台管理系统查看合同、教育平台展示试卷、审批系统预览发票等等。这类需求的核心目标就是:用户不需要下载,就能直接在页面中查看 PDF 文档内容

最近,我在公司的Vue3项目中刚好负责了一块PDF预览功能的开发,趁热打铁把这块功能的实现过程整理出来,希望能帮到有类似需求的朋友。

常见的 PDF 文件预览方式有哪些?

在查阅了一些资料,也踩了几个坑之后,我发现目前主流的三种方式大概如下:

实现方式简介优点缺点
iframe / embed 标签直接嵌入浏览器内核的渲染功能简单,不需要引入额外依赖样式和交互无法自定义,兼容性差
PDF.js(pdfjs-dist)由 Mozilla 出品的开源 PDF 渲染器,支持 canvas / svg 渲染功能强大,完全前端渲染,可高度定制实现略复杂,需要自己处理分页、缩放等逻辑
后端转图片将 PDF 转成图片给前端展示前端负担小,兼容性好没有文字层,不能选中、搜索、复制文字,服务端压力大

我最终选用的是 PDF.js(pdfjs-dist),原因很简单:其由 Mozilla 维护,稳定性强,功能完善,支持多页分页、缩放、搜索、高亮等能力。还有就是需求需要的是可以交互、可以选中文本的预览组件,而且尽量不依赖后端处理

开始动手:安装并配置 pdfjs-dist

先安装它:

npm install pdfjs-dist

然后,在我们自己的工具函数里,引入并配置好Web Worker路径(为了性能,PDF.js会用 worker异步解析):

import * as pdfjsLib from 'pdfjs-dist/build/pdf.mjs'

pdfjsLib.GlobalWorkerOptions.workerSrc = `https://cdn.jsdelivr.net/npm/pdfjs-dist@${(pdfjsLib as any).version}/build/pdf.worker.mjs`

注意:如果你用的是Vite,pdfjsworker不好自动打包,用CDN路径是目前最稳妥的方式。当然你也可以自行下载后配置本地路径。

核心功能封装:纯 JS 函数渲染PDF到DOM中

以下是我封装好的一个核心函数,接收PDF文件地址和容器DOM,然后渲染出完整PDF页内容。

// utils/pdfRenderer.ts
import * as pdfjsLib from 'pdfjs-dist/build/pdf.mjs'

pdfjsLib.GlobalWorkerOptions.workerSrc = `https://cdn.jsdelivr.net/npm/pdfjs-dist@${(pdfjsLib as any).version}/build/pdf.worker.mjs`

interface RenderPdfOptions {
  scale?: number
  page?: number
}

export async function renderPdfToContainer(
  container: HTMLElement,
  url: string,
  options?: RenderPdfOptions
) {
  container.innerHTML = ''

  const scale = options?.scale ?? 1.5
  const targetPage = options?.page

  try {
    const loadingTask = pdfjsLib.getDocument(url)
    const pdf = await loadingTask.promise

    const pages = targetPage
      ? [targetPage]
      : Array.from({ length: pdf.numPages }, (_, i) => i + 1)

    for (const pageNum of pages) {
      const page = await pdf.getPage(pageNum)
      const viewport = page.getViewport({ scale })

      const canvas = document.createElement('canvas')
      const context = canvas.getContext('2d')
      if (!context) continue

      canvas.width = viewport.width
      canvas.height = viewport.height
      container.appendChild(canvas)

      const renderContext = {
        canvasContext: context,
        viewport
      }

      await page.render(renderContext).promise
    }
  } catch (error) {
    console.error('PDF 加载失败:', error)
    container.innerHTML = '<p style="color:red">加载失败,请检查文件格式或地址是否正确。</p>'
  }
}

在 Vue3 组件中如何使用?

Vue3项目中写了一个简单组件,效果就是加载PDF文件并将其渲染到页面中:

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

<script setup lang="ts">
import { ref, onMounted } from 'vue'
import { renderPdfToContainer } from '@/utils/pdfRenderer'

const pdfWrapper = ref<HTMLElement>()
const pdfUrl = '/files/sample.pdf' // 替换成你的文件地址

onMounted(() => {
  if (pdfWrapper.value) {
    renderPdfToContainer(pdfWrapper.value, pdfUrl, { scale: 1.25 })
  }
})
</script>

<style scoped>
.pdf-container {
  width: 100%;
  overflow: auto;
  background: #f6f6f6;
  padding: 16px;
}
</style>

小提醒:为了避免渲染异常,renderPdfToContainer 必须在 onMounted 后 DOM 挂载后调用。

遇到的问题和一些解决方案

这里是开发过程中真实踩过的几个坑,顺手整理一下,希望你少走弯路。

问题一:加载失败,控制台报错 “Unexpected token '<'…”

原因PDF地址可能不对,返回的不是PDF,而是HTML错误页。 解决方式

  • 检查地址是不是404
  • fetch(url)看看实际返回内容是不是PDF

问题二:PDF渲染模糊,不清晰

原因canvas分辨率低或者devicePixelRatio没处理。 优化方法

const dpr = window.devicePixelRatio || 1
canvas.width = viewport.width * dpr
canvas.height = viewport.height * dpr
canvas.style.width = `${viewport.width}px`
canvas.style.height = `${viewport.height}px`
context.setTransform(dpr, 0, 0, dpr, 0, 0)

这样处理后,高清屏下也能展示得更清晰。

问题三:只想加载某一页怎么办?

直接传 page 参数:

renderPdfToContainer(dom, url, { page: 1 })

我自己在做分页加载的时候也用到了这个逻辑。

问题四:怎么支持本地文件预览(用户上传后立即预览)?

const reader = new FileReader()
reader.onload = async () => {
  const typedArray = new Uint8Array(reader.result as ArrayBuffer)
  const pdf = await pdfjsLib.getDocument({ data: typedArray }).promise
  // 同样调用 page.render 即可渲染
}
reader.readAsArrayBuffer(file)

这个写法可以用在 <input type="file"> 的上传场景。

小结一下

整个PDF文件解析功能,其实可以拆成三步:

  • 引入pdfjs-dist并设置好worker
  • 封装一个renderPdfToContainer函数做PDF渲染
  • Vue3项目中按需调用

整个过程其实不复杂,但很多资料都散着,或者讲得太官方,不太实用。我这次是花了些时间整理,并亲自踩坑测试的,如果你也有这类需求,希望这篇文章能让你少走几步弯路。

结语

Vue3项目中实现PDF预览并不难,但要实现 高性能、强交互、低资源占用 的用户体验,需要我们不断抽象渲染逻辑、优化性能瓶颈并兼顾跨平台适配。希望本文能帮助你快速掌握在Vue3中集成PDF.js的实战方案。

以上就是Vue3实现PDF文件解析与预览的完整实践的详细内容,更多关于Vue3 PDF解析与预览的资料请关注脚本之家其它相关文章!

相关文章

  • vue a标签点击实现赋值方式

    vue a标签点击实现赋值方式

    这篇文章主要介绍了vue a标签点击实现赋值方式,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-09-09
  • 全新打包工具parcel零配置vue开发脚手架

    全新打包工具parcel零配置vue开发脚手架

    parcel-vue 一个基于Parcel打包工具的 VueJS急速开发脚手架解决方案,强烈建议使用node8.0以上。下面通过本文给大家介绍全新打包工具parcel零配置vue开发脚手架的相关知识,感兴趣的朋友一起看看吧
    2018-01-01
  • ant-design-vue按需加载的坑的解决

    ant-design-vue按需加载的坑的解决

    这篇文章主要介绍了ant-design-vue按需加载的坑的解决,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-05-05
  • vue中动态select的使用方法示例

    vue中动态select的使用方法示例

    这篇文章主要介绍了vue中动态select的使用方法,结合实例形式分析了vue.js使用动态select创建下拉菜单相关实现技巧与操作注意事项,需要的朋友可以参考下
    2019-10-10
  • 一篇文章总结Vue3.2语法糖使用

    一篇文章总结Vue3.2语法糖使用

    Vue3.2(21年8月10日)相比于Vue3新增了语法糖,减少了代码冗余,下面这篇文章主要给大家介绍了关于Vue3.2语法糖使用的相关资料,文中通过实例代码介绍的非常详细,需要的朋友可以参考下
    2022-11-11
  • vue使用swiper实现中间大两边小的轮播图效果

    vue使用swiper实现中间大两边小的轮播图效果

    这篇文章主要介绍了vue使用swiper实现中间大两边小的轮播图效果,本文分步骤通过实例代码讲解的非常详细,需要的朋友可以参考下
    2019-11-11
  • 对VUE中的对象添加属性

    对VUE中的对象添加属性

    今天小编就为大家分享一篇对VUE中的对象添加属性,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2018-09-09
  • vue.js实现只弹一次弹框

    vue.js实现只弹一次弹框

    本篇文章通过代码实例给大家详细讲述了一个vue的实例,实现只弹一次弹框功能,一起学习分享下。
    2018-01-01
  • vue3点击出现弹窗后背景变暗且不可操作的实现代码

    vue3点击出现弹窗后背景变暗且不可操作的实现代码

    这篇文章主要介绍了vue3点击出现弹窗后背景变暗且不可操作的实现代码,本文通过实例代码图文相结合给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2022-08-08
  • vue中watch的实际开发学习笔记

    vue中watch的实际开发学习笔记

    watch是Vue实例的一个属性是用来响应数据的变化,需要在数据变化时执行异步或开销较大的操作时,这个方式是最有用的,下面这篇文章主要给大家介绍了关于vue中watch的实际开发笔记,需要的朋友可以参考下
    2022-11-11

最新评论