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

相关推荐
树叶会结冰10 分钟前
HTML语义化:当网页会说话
前端·html
冰万森16 分钟前
解决 React 项目初始化(npx create-react-app)速度慢的 7 个实用方案
前端·react.js·前端框架
牧羊人_myr29 分钟前
Ajax 技术详解
前端
浩男孩38 分钟前
🍀封装个 Button 组件,使用 vitest 来测试一下
前端
蓝银草同学42 分钟前
阿里 Iconfont 项目丢失?手把手教你将已引用的 SVG 图标下载到本地
前端·icon
布列瑟农的星空1 小时前
重学React —— React事件机制 vs 浏览器事件机制
前端
程序定小飞1 小时前
基于springboot的在线商城系统设计与开发
java·数据库·vue.js·spring boot·后端
一小池勺1 小时前
CommonJS
前端·面试
孙牛牛1 小时前
实战分享:一招解决嵌套依赖版本失控问题,以 undici 为例
前端