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表单绑定实现多选框和下拉列表的实例

    vue表单绑定实现多选框和下拉列表的实例

    本篇文章主要介绍了vue表单绑定实现多选框和下拉列表的实例,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-08-08
  • Vue3实现滚动条自动滚动到底部

    Vue3实现滚动条自动滚动到底部

    在Vue中,通过ref和watch结合nextTick实现滚动区域自动滚动到底部,并添加返回顶部按钮,适用于动态内容场景,供开发者参考
    2025-08-08
  • 组件库中使用 vue-i18n 国际化的案例详解

    组件库中使用 vue-i18n 国际化的案例详解

    这篇文章主要介绍了组件库中使用 vue-i18n 国际化,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2023-04-04
  • proxy代理不生效以及vue config.js不生效解决方法

    proxy代理不生效以及vue config.js不生效解决方法

    在开发Vue项目过程中,使用了Proxy代理进行数据劫持,但是在实际运行过程中发现代理并没有生效,也就是说数据并没有被劫持,这篇文章主要给大家介绍了关于proxy代理不生效以及vue config.js不生效解决方法的相关资料,需要的朋友可以参考下
    2023-11-11
  • springboot vue接口测试前端动态增删表单功能实现

    springboot vue接口测试前端动态增删表单功能实现

    这篇文章主要为大家介绍了springboot vue接口测试前端动态增删表单功能实现,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-05-05
  • Vue 与 Vuex 的第一次接触遇到的坑

    Vue 与 Vuex 的第一次接触遇到的坑

    在 Vue.js 的项目中,如果项目结构简单, 父子组件之间的数据传递可以使用 props 或者 $emit 等方式,如果是大型项目,很多时候都需要在子组件之间传递数据,使用vue的状态管理工具vuex很好的解决
    2018-08-08
  • Vue引用第三方datepicker插件无法监听datepicker输入框的值的解决

    Vue引用第三方datepicker插件无法监听datepicker输入框的值的解决

    这篇文章主要介绍了Vue引用第三方datepicker插件无法监听datepicker输入框的值的解决,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2018-01-01
  • vue3中做文件预览的项目实践

    vue3中做文件预览的项目实践

    本文主要介绍了在Vue3项目中实现常见文件类型的预览功能,包括docx、xlsx、pdf、txt、png、jpg、jpeg、mp4和mp3,具有一定的参考价值,感兴趣的可以了解一下
    2025-01-01
  • Vue微信小程序和uniapp配置环境地址

    Vue微信小程序和uniapp配置环境地址

    在微信小程序中,可以使用全局配置和使用开发、体验、生产环境的地址,这篇文章主要介绍了Vue微信和uniapp配置环境地址,需要的朋友可以参考下
    2023-07-07
  • vue中computed和watch的使用实例代码解析

    vue中computed和watch的使用实例代码解析

    这篇文章主要介绍了vue中computed和watch的综合运用实例,主要需求是点击按钮实现天气的切换效果结合示例代码给大家介绍的非常详细,需要的朋友可以参考下
    2022-04-04

最新评论