Vue3实现PDF文件预览 (低版本浏览器兼容)

前言:
        最近和小伙伴们一起合作完成一个企业级知识库项目,其中一个功能就是后端把所有格式的文件转换为PDF,前端实现渲染PDF文件从而实现预览,干了整整一周(考虑到低版本浏览器的兼容),试用了几种方案(iframe预览已被废弃,不适用本项目,想了解的同学自行搜索),终于实现了这个功能。

方案:Vue3+pdfjs-dist+canvas 

1.pdfjs-dist展示PDF文件的原理解释

pdfjs-dist展示pdf文档的原理,实际上是将pdf中的内容渲染到解析,然后渲染到 canvas 中进行展示,因此我们使用pdfjs渲染出来的pdf文件,实际上是一张张canvas图片。

2.安装pdfjs-dist

pdfjs-dist下载官网

Vue3实现PDF文件预览 (低版本浏览器兼容)_第1张图片

建议安装: "pdfjs-dist": "^2.12.313"

npm i [email protected]

打开VScode,使用ctl+`打开控制台,输入:npm i pdfjs-dist 安装pdfjs-dist 切记要指定版本

3. 搭建基础的页面代码

话不多说,上代码:

4.使用Vue3语法实现PDF文件的多页展示
4.1引入ref
import { onMounted, ref, reactive } from 'vue'
4.2将会用到的数据声明为响应式
const props = defineProps({
  pdfUrl: {
    type: String,
    default: '/testPdf.pdf',
    required: true,
  },
  containerWidth: {
    type: Number,
    default: 700,
    required: true,
  },
});

const pdfParams = reactive({
  currentPageNumber: 1,
  pdfScale: 1.0,
  pdfPageTotal: 0, // 总页数
});

// 不要定义为ref或reactive格式,就定义为普通的变量
let pdfDoc = null;
4.3定义获取pdf文档流与pdf文件的页数的方法:loadFile
// 这里必须使用异步去引用pdf文件,直接去import会报错,也不知道为什么
const loadFile = async () => {
  let pdfjs = await import('pdfjs-dist/build/pdf')
  let pdfjsWorker = await import('pdfjs-dist/build/pdf.worker.entry')
  pdfjs.GlobalWorkerOptions.workerSrc = pdfjsWorker
  // 此文件位于public/testPdf.pdf
  pdfjs.getDocument(props.pdfUrl).promise.then(async doc => {
    pdfDoc = doc
    pdfParams.pdfPageTotal = doc.numPages
    // // 仅加载第一页  注释  取消页码切换
    // await getPdfPage(pdfParams.currentPageNumber)
    // 加载pdf所有页
    for (let pageNum = 1; pageNum <= doc.numPages; pageNum++) {
      await getPdfPage(pageNum)
    }
  })
}
4.4定义渲染pdf文件的方法:renderPage
// 加载pdf的某一页
const getPdfPage = (number) => {
  return new Promise((resolve, reject) => {
    pdfDoc.getPage(number).then(page => {
      const canvas = document.getElementById(`pdf-render${number}`)
      const context = canvas.getContext('2d')
      const scale = 1; // 缩放比例
      const dpr = window.devicePixelRatio || 1;
      const bsr =
        context.webkitBackingStorePixelRatio ||
        context.mozBackingStorePixelRatio ||
        context.msBackingStorePixelRatio ||
        context.oBackingStorePixelRatio ||
        context.backingStorePixelRatio ||
        1;
      const ratio = dpr / bsr;
      const viewport = page.getViewport({ scale: pdfParams.pdfScale }); // 获取窗口大小
      const canvasWidth = Math.floor(viewport.width * ratio);
      const canvasHeight = Math.floor(viewport.height * ratio);
      // const canvasWidth = props.containerWidth;
      // const canvasHeight = Math.floor(viewport.height * ratio) * (props.containerWidth / Math.floor(viewport.width * ratio));
      canvas.width = canvasWidth;
      canvas.height = canvasHeight;
      // canvas.style.width = Math.floor(viewport.width) + 'px'
      // canvas.style.height = Math.floor(viewport.height) + 'px'
      canvas.style.width = Math.floor(props.containerWidth) + 'px'
      canvas.style.height = Math.floor(viewport.height * props.containerWidth / viewport.width) + 'px'

      let renderContext = {
        canvasContext: context,
        viewport: viewport,
        // 这里transform的六个参数,使用的是transform中的Matrix(矩阵)
        // transform: [1, 0, 0, -1, 0, viewport.height]
        transform: [ratio, 0, 0, ratio, 0, 0]
      }

      // 进行渲染
      page.render(renderContext).promise.then(() => {
        resolve();
      }).catch(error => {
        reject(error);
      });
    }).catch(error => {
      reject(error);
    });
  });
}
4.5在onMounted钩子中调用loadFile方法
//调用loadFile方法
onMounted(async () => {
  await loadFile()
})
5完整代码实现:







以上就是实现PDF文件多页展示的内容了,如果其他的小伙伴有其他的方法或者思考请批评指正 

你可能感兴趣的:(JavaScript,vue,pdf)