vue使用pdf.js预览pdf文件的方法是什么

发布时间:2021-12-20 16:33:30 作者:iii
来源:亿速云 阅读:236
# 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>

2.2 配置worker路径

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'

三、基础PDF预览实现

3.1 组件化实现方案

创建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>

3.2 使用示例

<template>
  <div>
    <PdfViewer pdfUrl="/sample.pdf" />
  </div>
</template>

<script>
import PdfViewer from '@/components/PdfViewer.vue'

export default {
  components: {
    PdfViewer
  }
}
</script>

四、高级功能实现

4.1 添加缩放控制

在组件中添加缩放功能:

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)
  }
}

4.2 文本图层渲染

实现可选择的文本层:

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: []
  })
}

4.3 缩略图导航

添加侧边栏缩略图:

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)
}

五、性能优化方案

5.1 页面预加载

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)
      }
    }
  }
}

5.2 内存管理

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)
      }
    })
  }
}

六、常见问题解决方案

6.1 CORS问题处理

async loadPdf() {
  const loadingTask = pdfjsLib.getDocument({
    url: this.pdfUrl,
    withCredentials: true,  // 携带cookie
    httpHeaders: {         // 自定义头
      'Authorization': 'Bearer xxx'
    }
  })
  // ...
}

6.2 大文件分片加载

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标注功能 - 添加全文搜索 - 集成打印/下载功能 - 支持多文档对比查看 “`

推荐阅读:
  1. vue如何使用vue-pdf实现pdf在线预览
  2. 使用vue实现在线预览pdf文件和下载的方法

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

vue pdf.js

上一篇:JavaScript数组中的深复制与浅复制是什么

下一篇:Python中Playwright怎么用

相关阅读

您好,登录后才能下订单哦!

密码登录
登录注册
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》