Vue 3 中使用 vue - pdf - embed + vue3 - pdfjs 在线预览 PDF

在许多 Web 应用程序中,需要实现 PDF 文件的在线预览功能。Vue 3 作为流行的前端框架,配合 vue - pdf - embed 和 vue3 - pdfjs 库,可以轻松实现这一需求。本文将详细介绍如何在 Vue 3 项目中使用这两个库进行 PDF 在线预览。

完整代码实现及演示效果请参考开源项目:vue3-pc-template

一、环境准备

确保你已经创建了一个 Vue 3 项目,并且安装了相关依赖。如果没有安装 vue - pdf - embed 和 vue3 - pdfjs,可以通过以下命令进行安装:

bash 复制代码
npm install vue - pdf - embed vue3 - pdfjs

二、代码实现

(一)父组件中使用

javascript 复制代码
<template>

<div class="pdf-container">

<PDFView :pdfUrl="jsPdf" />

</div>

</template>

<script setup>

import PDFView from "@/components/PdfPreview/index.vue";

import jsPdf from "/pdf/test.pdf"; // 本地地址

// const jsPdf = 'http://localhost/test.pdf' // 线上地址也可,但需要注意跨域问题

</script>

<style scoped>

.pdf-container {

overflow: auto;

}

</style>
1、 template部分

在<template>中,创建了一个div容器,类名为pdf - container,用于包裹 PDF 预览组件PDFView。并通过:pdfUrl属性将jsPdf传递给子组件PDFView。

2、 script部分

引入PDFView组件,同时定义了jsPdf变量,它可以是本地 PDF 文件路径(如/pdf/test.pdf),也可以是线上地址(但要注意跨域问题)。

3、 style部分

给pdf - container添加overflow: auto样式,以便在内容超出容器大小时出现滚动条。

(二)将实现逻辑封装成子组件

复制代码
@/components/PdfPreview/index.vue
javascript 复制代码
<template>

<div class="pdf-preview">

<div id="page - view" :style="{

position: 'absolute',

top: '50%',

left: '50%',

transform: `translate(-50%, -50%) scale(${state.scale})`,

width: '100%',

height: `${pageHeight}`,

}">

<vue - pdf - embed :source="state.source" :page="state.pageNum" textLayer />

</div>

</div>

<div class="page - tool">

<div class="page - tool - item" @click="lastPage">上一页</div>

<div class="page - tool - item" @click="nextPage">下一页</div>

<div class="page - tool - item">{{ state.pageNum }}/{{ state.numPages }}</div>

<div class="page - tool - item" @click="pageZoomOut">放大</div>

<div class="page - tool - item" @click="pageZoomIn">缩小</div>

</div>

</template>

<script setup lang="ts">

import { reactive, onMounted, ref } from "vue";

import VuePdfEmbed from "vue - pdf - embed";

import { createLoadingTask } from "vue3 - pdfjs";

const props = defineProps({

pdfUrl: {

type: String,

required: true,

},

});

const pageHeight = ref('100%');

const state = reactive({

source: props.pdfUrl, //预览pdf文件地址

pageNum: 1, //当前页面

scale: 1, // 缩放比例

numPages: 0, // 总页数

});

function lastPage() {

if (state.pageNum > 1) {

state.pageNum -= 1;

}

}

function nextPage() {

if (state.pageNum < state.numPages) {

state.pageNum += 1;

}

}

function pageZoomOut() {

if (state.scale < 2) {

state.scale += 0.1;

pageHeight.value = (parseInt(pageHeight.value) - 5.0) + '%';

}

}

function pageZoomIn() {

if (state.scale > 1) {

state.scale -= 0.1;

pageHeight.value = (parseInt(pageHeight.value) + 5.0) + '%';

}

}

onMounted(() => {

const loadingTask = createLoadingTask(state.source);

loadingTask.promise.then((pdf: { numPages: number }) => {

state.numPages = pdf.numPages;

});

});

</script>

<style lang="css" scoped>

.pdf-preview {

position: relative;

height: 100vh;

padding: 20px 0;

box-sizing: border-box;

background-color: e9e9e9;

}

.pdf-wrap {

overflow-y: auto;

}

.vue - pdf - embed {

text-align: center;

width: 515px;

border: 1px solid #e5e5e5;

margin: 0 auto;

box-sizing: border-box;

}

.page - tool {

position: absolute;

bottom: 35px;

padding-left: 15px;

padding-right: 15px;

display: flex;

align-items: center;

background: rgb(66, 66, 66);

color: white;

border-radius: 19px;

z-index: 100;

cursor: pointer;

margin-left: 50%;

transform: translateX(-50%);

}

.page - tool - item {

padding: 8px 15px;

padding-left: 10px;

cursor: pointer;

}

</style>
1、 template部分
  • 创建了一个div容器,类名为pdf - preview,作为整体的预览区域,设置了相对定位和一些基本样式。
  • 在pdf - preview内部,有一个div,id为page - view,通过:style绑定动态样式,实现居中显示和缩放效果。在这个div内部,使用vue - pdf - embed组件,通过:source属性传递 PDF 文件地址,:page属性传递当前显示的页码,并启用textLayer。
  • 下方还有一个div,类名为page - tool,用于显示页面切换和缩放的工具按钮。每个按钮通过@click绑定相应的方法。
2、 script部分
  • 引入 Vue 的reactive、onMounted、ref等函数,以及vue - pdf - embed和vue3 - pdfjs中的createLoadingTask。
  • 通过defineProps定义接收父组件传递的pdfUrl属性,并且设置为必填。
  • 使用ref定义pageHeight变量,初始值为100%,用于控制预览区域的高度。
  • 使用reactive定义state对象,包含source(PDF 文件地址)、pageNum(当前页码)、scale(缩放比例)、numPages(总页数)等属性。
  • 定义了lastPage、nextPage、pageZoomOut、pageZoomIn等方法,分别用于上一页、下一页、放大、缩小的功能实现。
  • 在onMounted钩子函数中,通过createLoadingTask创建加载任务,获取 PDF 文件的总页数并更新state.numPages。
3、 样式部分
  • 给pdf - preview设置背景色、高度、内边距等样式。
  • 给vue - pdf - embed设置居中显示、边框、宽度等样式。
  • 给page - tool设置绝对定位、背景色、圆角、水平居中对齐等样式,给page - tool - item设置内边距和鼠标指针样式。

三、注意事项

1、 跨域问题

如果使用线上地址,需要确保服务器端设置了正确的跨域策略,否则会出现跨域请求失败的问题。可以通过在服务器端配置 CORS(跨域资源共享)来解决。

2、 文件路径

确保本地 PDF 文件路径正确,并且在打包和部署时,文件能够正确被访问到。

完整代码实现请参考开源项目:vue3-pc-template

欢迎 Star 和 Fork 项目,一起构建更完善的权限管理体系!

相关推荐
拾光拾趣录8 分钟前
for..in 和 Object.keys 的区别:从“遍历对象属性的坑”说起
前端·javascript
OpenTiny社区19 分钟前
把 SearchBox 塞进项目,搜索转化率怒涨 400%?
前端·vue.js·github
编程猪猪侠1 小时前
Tailwind CSS 自定义工具类与主题配置指南
前端·css
qhd吴飞1 小时前
mybatis 差异更新法
java·前端·mybatis
YGY Webgis糕手之路1 小时前
OpenLayers 快速入门(九)Extent 介绍
前端·经验分享·笔记·vue·web
患得患失9491 小时前
【前端】【vueDevTools】使用 vueDevTools 插件并修改默认打开编辑器
前端·编辑器
ReturnTrue8681 小时前
Vue路由状态持久化方案,优雅实现记住表单历史搜索记录!
前端·vue.js
UncleKyrie1 小时前
一个浏览器插件帮你查看Figma设计稿代码图片和转码
前端
遂心_1 小时前
深入解析前后端分离中的 /api 设计:从路由到代理的完整指南
前端·javascript·api
你听得到112 小时前
Flutter - 手搓一个日历组件,集成单日选择、日期范围选择、国际化、农历和节气显示
前端·flutter·架构