# Vue使用pdf.js預覽PDF文件的方法是什么
PDF.js是Mozilla開發的一個基于Web標準的PDF閱讀器庫,無需任何插件即可在現代瀏覽器中渲染PDF文檔。本文將詳細介紹在Vue項目中集成pdf.js實現PDF預覽的完整方案。
## 一、pdf.js簡介與核心概念
### 1.1 什么是pdf.js
PDF.js是一個使用HTML5構建的PDF閱讀器,主要包含兩個核心部分:
- **PDF解析器**:將二進制PDF數據轉換為可操作的文檔對象
- **PDF渲染器**:使用Canvas/HTML將文檔渲染到網頁上
### 1.2 核心特性
- 純前端解決方案
- 支持文本選擇、搜索
- 支持縮放、旋轉等查看操作
- 開源免費(Apache License 2.0)
## 二、基礎環境準備
### 2.1 安裝pdf.js
在Vue項目中可以通過npm安裝:
```bash
npm install pdfjs-dist
或通過CDN引入:
<script src="https://cdnjs.cloudflare.com/ajax/libs/pdf.js/2.10.377/pdf.min.js"></script>
PDF.js使用Web Worker進行后臺解析,需要單獨配置:
import * as pdfjsLib from 'pdfjs-dist'
// 開發環境
pdfjsLib.GlobalWorkerOptions.workerSrc =
require('pdfjs-dist/build/pdf.worker.min.js')
// 生產環境建議使用CDN
// pdfjsLib.GlobalWorkerOptions.workerSrc =
// 'https://cdnjs.cloudflare.com/ajax/libs/pdf.js/2.10.377/pdf.worker.min.js'
創建PdfViewer.vue
組件:
<template>
<div class="pdf-container">
<canvas ref="pdfCanvas"></canvas>
<div class="page-controls">
<button @click="prevPage">上一頁</button>
<span>第 {{ currentPage }} / {{ pageCount }} 頁</span>
<button @click="nextPage">下一頁</button>
</div>
</div>
</template>
<script>
import * as pdfjsLib from 'pdfjs-dist'
export default {
props: {
pdfUrl: {
type: String,
required: true
}
},
data() {
return {
pdfDoc: null,
currentPage: 1,
pageCount: 0,
renderTask: null,
scale: 1.5
}
},
methods: {
async loadPdf() {
try {
// 加載PDF文檔
const loadingTask = pdfjsLib.getDocument(this.pdfUrl)
this.pdfDoc = await loadingTask.promise
this.pageCount = this.pdfDoc.numPages
this.renderPage(this.currentPage)
} catch (err) {
console.error('PDF加載失敗:', err)
}
},
async renderPage(num) {
if (this.renderTask) {
await this.renderTask.cancel()
}
const page = await this.pdfDoc.getPage(num)
const viewport = page.getViewport({ scale: this.scale })
const canvas = this.$refs.pdfCanvas
const context = canvas.getContext('2d')
canvas.height = viewport.height
canvas.width = viewport.width
this.renderTask = page.render({
canvasContext: context,
viewport: viewport
})
await this.renderTask.promise
},
prevPage() {
if (this.currentPage <= 1) return
this.currentPage--
this.renderPage(this.currentPage)
},
nextPage() {
if (this.currentPage >= this.pageCount) return
this.currentPage++
this.renderPage(this.currentPage)
}
},
mounted() {
this.loadPdf()
},
watch: {
pdfUrl() {
this.loadPdf()
}
}
}
</script>
<style scoped>
.pdf-container {
margin: 20px auto;
max-width: 800px;
}
canvas {
border: 1px solid #eee;
box-shadow: 0 0 5px rgba(0,0,0,0.1);
margin-bottom: 10px;
}
.page-controls {
display: flex;
justify-content: center;
align-items: center;
gap: 15px;
}
button {
padding: 5px 15px;
cursor: pointer;
}
</style>
<template>
<div>
<PdfViewer pdfUrl="/sample.pdf" />
</div>
</template>
<script>
import PdfViewer from '@/components/PdfViewer.vue'
export default {
components: {
PdfViewer
}
}
</script>
在組件中添加縮放功能:
methods: {
zoomIn() {
this.scale *= 1.2
this.renderPage(this.currentPage)
},
zoomOut() {
if (this.scale <= 0.5) return
this.scale /= 1.2
this.renderPage(this.currentPage)
}
}
實現可選擇的文本層:
async renderPage(num) {
// ...原有canvas渲染代碼...
// 添加文本層
const textLayer = document.createElement('div')
textLayer.className = 'text-layer'
this.$refs.pdfCanvas.parentNode.appendChild(textLayer)
const textContent = await page.getTextContent()
await pdfjsLib.renderTextLayer({
textContent: textContent,
container: textLayer,
viewport: viewport,
textDivs: []
})
}
添加側邊欄縮略圖:
async loadPdf() {
// ...原有代碼...
this.generateThumbnails()
},
async generateThumbnails() {
const container = document.createElement('div')
container.className = 'thumbnail-container'
for (let i = 1; i <= this.pageCount; i++) {
const page = await this.pdfDoc.getPage(i)
const viewport = page.getViewport(0.5)
const canvas = document.createElement('canvas')
const context = canvas.getContext('2d')
canvas.height = viewport.height
canvas.width = viewport.width
canvas.onclick = () => {
this.currentPage = i
this.renderPage(i)
}
await page.render({
canvasContext: context,
viewport: viewport
}).promise
container.appendChild(canvas)
}
document.querySelector('.pdf-container').appendChild(container)
}
data() {
return {
// ...其他數據...
preloadedPages: new Map()
}
},
methods: {
async preloadAdjacentPages() {
const pagesToPreload = [
this.currentPage + 1,
this.currentPage + 2
].filter(p => p <= this.pageCount)
for (const pageNum of pagesToPreload) {
if (!this.preloadedPages.has(pageNum)) {
const page = await this.pdfDoc.getPage(pageNum)
this.preloadedPages.set(pageNum, page)
}
}
}
}
methods: {
cleanupPages() {
// 保留當前頁和前后兩頁
const pagesToKeep = new Set([
this.currentPage,
this.currentPage - 1,
this.currentPage + 1
].filter(p => p >= 1 && p <= this.pageCount))
this.preloadedPages.forEach((_, pageNum) => {
if (!pagesToKeep.has(pageNum)) {
this.preloadedPages.delete(pageNum)
}
})
}
}
async loadPdf() {
const loadingTask = pdfjsLib.getDocument({
url: this.pdfUrl,
withCredentials: true, // 攜帶cookie
httpHeaders: { // 自定義頭
'Authorization': 'Bearer xxx'
}
})
// ...
}
async loadLargePdf() {
const response = await fetch(this.pdfUrl)
const contentLength = response.headers.get('Content-Length')
const chunkSize = 1024 * 1024 // 1MB分片
let received = 0
const chunks = []
const reader = response.body.getReader()
while(received < contentLength) {
const { done, value } = await reader.read()
if (done) break
chunks.push(value)
received += value.length
// 可以在這里更新加載進度
this.loadProgress = (received / contentLength) * 100
}
const pdfData = new Uint8Array(received)
let position = 0
for(const chunk of chunks) {
pdfData.set(chunk, position)
position += chunk.length
}
const loadingTask = pdfjsLib.getDocument(pdfData)
// ...
}
/src
/components
PdfViewer.vue # PDF查看器組件
PdfThumbnails.vue # 縮略圖組件
PdfControls.vue # 控制欄組件
/utils
pdf-loader.js # PDF加載工具函數
/views
PdfPreview.vue # 預覽頁面
本文詳細介紹了在Vue項目中集成pdf.js的完整方案,包括: 1. 基礎PDF渲染實現 2. 高級功能如文本選擇、縮略圖等 3. 性能優化技巧 4. 常見問題解決方案
通過組件化的實現方式,可以輕松地在不同Vue項目中復用PDF預覽功能。pdf.js的強大功能結合Vue的響應式特性,能夠構建出體驗良好的PDF閱讀解決方案。
對于更復雜的需求,還可以考慮: - 實現PDF標注功能 - 添加全文搜索 - 集成打印/下載功能 - 支持多文檔對比查看 “`
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。