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 项目,一起构建更完善的权限管理体系!

相关推荐
dogodo5 分钟前
强迫症之保持干净的 $HOME 目录
前端
前端大卫9 分钟前
【Chrome 官方示例】🔥手把手教你解锁 Performace 选项卡
前端·javascript·性能优化
小樱花sakura10 分钟前
3D玫瑰图
前端
苏州第一深情12 分钟前
SpeechSynthesisUtterance文字语音播报, 循环播报, 方法封装多组件使用, 自定义播报音色音量音调
前端·javascript·vue.js
JiangJiang14 分钟前
Vue3源码:5个问题带你读懂watch
javascript·vue.js·面试
程序员老冯头18 分钟前
第七节 MATLAB数据类型
开发语言·前端·数据结构·python·算法·matlab·信息可视化
OpenTiny社区19 分钟前
Node.js技术原理分析系列6——基于 V8 封装一个自己的 JavaScript 运行时
前端·node.js
openInula前端开源社区20 分钟前
【openInula茶话会】第一期:前端框架openInula整体介绍
前端·vue.js
如此风景20 分钟前
TypeScript中的Record
javascript
前端九哥21 分钟前
vue3实现复制到剪切板
前端·vue.js