你好,Vue 开发者们!
在 Web 开发中,我们经常会遇到需要在页面中直接展示 PDF 文件的需求,例如预览合同、显示报告或在线阅读文档。你可能会想到用 <iframe>
或者一些重量级的库,但它们往往不够灵活或过于臃肿。
今天,我将向你介绍一个轻量、强大且对 Vue 3 非常友好的解决方案——vue-pdf-embed
。
🤔 vue-pdf-embed
是什么?
vue-pdf-embed
是一个专门为 Vue 设计的 PDF 查看器组件。它基于 Mozilla 的 PDF.js,但去除了所有不必要的 UI 和复杂性,只专注于提供一个纯粹、高性能的 PDF 渲染核心。
核心亮点:
- 📦 轻量级:只包含渲染 PDF 所需的核心逻辑,打包体积小。
- 🖼️ 高质量渲染:利用 PDF.js,确保 PDF 内容清晰、准确地显示。
- 📱 响应式:能够很好地适应不同尺寸的容器。
- 🔧 高度可控:通过 Props 和事件,你可以完全控制 PDF 的渲染行为,如页码、缩放、旋转等。
- ✨ Vue 3 兼容:完美支持 Vue 3 的组合式 API 和
<script setup>
语法。
🛠️ 安装
将 vue-pdf-embed
添加到你的项目中非常简单:
npm install vue-pdf-embed
🚀 快速上手:三分钟渲染你的第一个 PDF
集成 vue-pdf-embed
只需要几行代码。
1. 引入组件
<script setup>
import VuePdfEmbed from "vue-pdf-embed";
</script>
2. 在模板中使用
你需要提供一个 source
属性,指向你的 PDF 文件。它可以是一个 URL、Base64 字符串或 ArrayBuffer。
<template>
<VuePdfEmbed
source="https://raw.githubusercontent.com/mozilla/pdf.js/master/web/compressed.tracemonkey-pldi-09.pdf"
/>
</template>
就这样!一个 PDF 查看器已经成功渲染在你的页面上了。是不是超级简单?
✨ 进阶实战:打造一个功能齐全的 PDF 查看器
当然,仅仅显示 PDF 是不够的。我们通常需要分页、缩放等功能。下面,我们将创建一个更完整的 PDF 查看器组件。
核心思路
- 加载 PDF:监听
@loaded
事件,在 PDF 加载完成后获取总页数。 - 分页控制:创建“上一页”和“下一页”按钮,通过修改
page
prop 来切换页面。 - 缩放控制:创建“放大”和“缩小”按钮,通过修改
scale
prop 来调整视图大小。 - 状态显示:显示当前页码和总页数。
完整代码示例 (PdfViewer.vue
)
<template>
<div class="pdf-viewer-container">
<!-- 控制栏 -->
<div class="controls">
<button @click="prevPage" :disabled="page <= 1">上一页</button>
<span>第 {{ page }} / {{ pageCount }} 页</span>
<button @click="nextPage" :disabled="page >= pageCount">下一页</button>
<button @click="zoomOut" :disabled="scale <= 0.5">缩小</button>
<span>缩放: {{ Math.round(scale * 100) }}%</span>
<button @click="zoomIn" :disabled="scale >= 2">放大</button>
</div>
<!-- PDF 渲染区域 -->
<div class="pdf-wrapper">
<VuePdfEmbed
ref="pdfRef"
:source="pdfSource"
:page="page"
:scale="scale"
@loaded="handleDocumentLoaded"
@rendering-failed="handleRenderingFailed"
/>
</div>
</div>
</template>
<script setup>
import { ref, watch } from "vue";
import VuePdfEmbed from "vue-pdf-embed";
// PDF 文件源
const pdfSource = ref(
"https://raw.githubusercontent.com/mozilla/pdf.js/master/web/compressed.tracemonkey-pldi-09.pdf"
);
// PDF 组件引用
const pdfRef = ref(null);
// PDF 状态
const page = ref(1);
const pageCount = ref(0);
const scale = ref(1);
// PDF 加载完成回调
function handleDocumentLoaded(pdf) {
console.log("PDF 加载完成!", pdf);
pageCount.value = pdf.numPages;
}
// PDF 渲染失败回调
function handleRenderingFailed(error) {
console.error("PDF 渲染失败:", error);
}
// 分页功能
function prevPage() {
if (page.value > 1) {
page.value--;
}
}
function nextPage() {
if (page.value < pageCount.value) {
page.value++;
}
}
// 缩放功能
function zoomIn() {
if (scale.value < 2) {
scale.value += 0.25;
}
}
function zoomOut() {
if (scale.value > 0.5) {
scale.value -= 0.25;
}
}
// 监听页码变化,确保在范围内
watch(page, (newPage) => {
if (newPage < 1) {
page.value = 1;
}
if (newPage > pageCount.value && pageCount.value > 0) {
page.value = pageCount.value;
}
});
</script>
<style scoped>
.pdf-viewer-container {
max-width: 900px;
margin: 2rem auto;
border: 1px solid #ccc;
border-radius: 8px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}
.controls {
display: flex;
justify-content: center;
align-items: center;
gap: 1rem;
padding: 1rem;
background-color: #f5f5f5;
border-bottom: 1px solid #ccc;
border-radius: 8px 8px 0 0;
}
.controls button {
padding: 0.5rem 1rem;
border: 1px solid #ddd;
border-radius: 4px;
background-color: #fff;
cursor: pointer;
}
.controls button:disabled {
cursor: not-allowed;
opacity: 0.5;
}
.controls span {
font-size: 0.9rem;
min-width: 100px;
text-align: center;
}
.pdf-wrapper {
height: 70vh;
overflow: auto;
background-color: #e9e9e9;
padding: 1rem;
}
/* vue-pdf-embed 的内部样式,我们可以覆盖它 */
:deep(.vue-pdf-embed > div) {
margin-bottom: 8px;
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
}
</style>

常用 Props 和事件
- Props:
source
: PDF 文件来源 (URL, Base64, Uint8Array, …)。page
: (Number) 要显示的页码。scale
: (Number) 缩放比例。rotation
: (Number) 旋转角度 (0, 90, 180, 270)。width
: (Number | String) 容器宽度。height
: (Number | String) 容器高度。- Events:
@loaded
: PDF 文档加载完成时触发,回调参数为 PDF.js 的文档对象,可以从中获取总页数numPages
等信息。@rendered
: 所有可见页面渲染完成时触发。@rendering-failed
: 渲染失败时触发。@password-requested
: 当 PDF 需要密码时触发。
总结
vue-pdf-embed
为在 Vue 应用中嵌入 PDF 提供了一个极其简单而又强大的解决方案。它避免了 <iframe>
的笨重和同源策略问题,也比一些重量级 UI 库更轻量、更灵活。
通过组合其 Props 和事件,你可以轻松构建出符合业务需求的、交互丰富的 PDF 查看器。如果你正在寻找一个可靠的 Vue PDF 渲染方案,vue-pdf-embed
绝对是你的不二之选。
原文链接:https://code.ifrontend.net/archives/1218,转载请注明出处。
评论0