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

这篇具有很好参考价值的文章主要介绍了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文件预览 (低版本浏览器兼容),JavaScript,vue,pdf

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

npm i pdfjs-dist@2.12.313

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

3. 搭建基础的页面代码

话不多说,上代码:

<template>
  <div class="pdf-preview-box">
    <!-- <div class="pdf_down">
          <div class="pdf_set_left" @click="scaleD()">放大</div>
          <div class="pdf_set_middle" @click="scaleX()">缩小</div>
          <div class="pdf-pre" @click="prePage">上一页</div>
          <div class="pdf-next" @click="nextPage">下一页</div>
      </div> -->
    <canvas class="pdf-viewer"
        v-for="i in pdfParams.pdfPageTotal"
        :key="i"
        :id="'pdf-render' + i">
    </canvas>
  </div>
</template>
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完整代码实现:
<!--
 * @Author: 码农键盘上的梦
 * @Description:  pdf预览插件    "pdfjs-dist": "^2.12.313",  指定版本 配合 canvas 实现一个组件
 * 
-->
<template>
  <div class="pdf-preview-box">
    <!-- <div class="pdf_down">
          <div class="pdf_set_left" @click="scaleD()">➕</div>
          <div class="pdf_set_middle" @click="scaleX()">➖</div>
          <div class="pdf-pre" @click="prePage">上一页</div>
          <div class="pdf-next" @click="nextPage">下一页</div>
      </div> -->
    <canvas class="pdf-viewer" v-for="i in pdfParams.pdfPageTotal" :key="i" :id="'pdf-render' + i"></canvas>
  </div>
</template>

<script setup>
import { onMounted, ref, reactive } from 'vue'

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;

onMounted(async () => {
  await 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)
    }
  })
}

// 加载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);
    });
  });
}


// // 下一页功能
// const prevPage = () => {
//     if (pdfParams.currentPageNumber > 1) {
//         pdfParams.currentPageNumber -= 1
//     } else {
//         pdfParams.currentPageNumber = 1
//     }
//     getPdfPage(pdfParams.currentPageNumber)
// }
// // 上一页功能
// const nextPage = () => {
//     if (pdfParams.currentPageNumber < pdfParams.pdfPageTotal) {
//         pdfParams.currentPageNumber += 1
//     } else {
//         pdfParams.currentPageNumber = pdfParams.pdfPageTotal
//     }
//     getPdfPage(pdfParams.currentPageNumber)
// }

// //放大
// const scaleD = async () => {
//     let max = 0;
//     if (window.screen.width > 1440) {
//         max = 1.4;
//     } else {
//         max = 1.2;
//     }
//     if (pdfParams.pdfScale >= max) {
//         return;
//     }
//     pdfParams.pdfScale = pdfParams.pdfScale + 0.1;
//     await loadFile();
// }
// //缩小
// const scaleX = async () => {
//     let min = 1.0;
//     if (pdfParams.pdfScale <= min) {
//         return;
//     }
//     pdfParams.pdfScale = pdfParams.pdfScale - 0.1;
//     await loadFile();
// }

</script>

<style scoped lang="scss" >
.pdf-preview-box {
  width: 100%;
  position: relative;

  // .pdf_down {
  //     position: fixed;
  //     display: flex;
  //     z-index: 20;
  //     right: 26px;
  //     bottom: 7%;
  //     cursor: pointer;

  //     .pdf_set_left {
  //         width: 30px;
  //         height: 40px;
  //         color: #408fff;
  //         font-size: 15px;
  //         padding-top: 25px;
  //         text-align: center;
  //         margin-right: 5px;
  //         cursor: pointer;
  //     }

  //     .pdf_set_middle {
  //         width: 30px;
  //         height: 40px;
  //         color: #408fff;
  //         font-size: 15px;
  //         padding-top: 25px;
  //         text-align: center;
  //         margin-right: 5px;
  //         cursor: pointer;
  //     }

  //     .pdf-pre {
  //         position: fixed;
  //         display: flex;
  //         z-index: 20;
  //         right: 160px;
  //         bottom: 9%;
  //         cursor: pointer;
  //     }

  //     .pdf-next {
  //         position: fixed;
  //         display: flex;
  //         z-index: 20;
  //         right: 100px;
  //         bottom: 9%;
  //     }
  // }
}
</style>

以上就是实现PDF文件多页展示的内容了,如果其他的小伙伴有其他的方法或者思考请批评指正 文章来源地址https://www.toymoban.com/news/detail-806839.html

到了这里,关于Vue3实现PDF文件预览 (低版本浏览器兼容)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Vue3 实现文件预览 Word Excel pdf 图片 视频等格式 大全!!!!

    先上效果图    插件安装 先说 word 文件是docx-preview插件           excel文件是用 xlsx 插件     介绍后端返回的数据 因为在拦截器处 做了对数据的处理 最后你调接口拿到的数据是 一个对象 里面包含: url :  blob对象转换的用于访问 Blob 数据的临时链接。这个链接可以被用于

    2024年02月07日
    浏览(50)
  • 微信公众号 - 实现 H5 网页在微信内置浏览器中下载文件,可预览和下载 office 文件(doc / xls / ppt / pdf 等)适用于任何前端技术栈网站,兼容安卓和苹果系统!

    网上的教程都是让你写页面 “引导” 右上角三个点里,让用户自己去浏览器打开,其实这样用户体验并不好。 本文实现了 最新微信公众号 H5 网页(微信内置浏览器中),预览下载 office 文件,安卓和苹果全都支持! 您可以直接复制代码,移植到自己项目中去, 任何前端项

    2024年01月21日
    浏览(60)
  • 浏览器预览pdf

    最近开发手机端的时候遇到安卓浏览器用a /标签href为pdf链接的时候 它不给我去预览pdf而是要我下载,这可离了大普. 我想到的最快的解决方案就是把pdf转换成html文件展示 PDF转换为HTML - 迅捷,在线,免费 - PDF24 Tools 将pdf文件转成html文件放在静态目录下 在用a标签跳转就行

    2024年01月24日
    浏览(41)
  • 前端vue3实现本地及在线文件预览(含pdf/txt/mp3/mp4/docx/xlsx/pptx)

    (一)微软office免费预览( 推荐 ) 支持doc/docx/xls/xlsx/ppt/pptx等多种office文件格式的免费预览 (二)XDOC文档预览云服务  移动端和PC端无插件预览PDF、OFD、Word、WPS等多种格式文档 本地或内网预览需要借助插件实现,pdf、mp3、mp4等主要靠原生标签或浏览器自带功能,尽量减少

    2024年02月05日
    浏览(55)
  • vue3移动端实现pdf预览

    使用的插件有: html部分: js部分: 我一开始使用的时第一种方法,然后测试之后发现 苹果手机会显示pdf加载出错了 ,安卓手机可以正常显示,于是换成了第二种方法。 html部分: js部分: 用了第二种插件后,苹果手机还是加载不出来,后面查到因为pdfjs-dist有时候会出现部

    2024年02月02日
    浏览(37)
  • pdfjs解决ie浏览器预览pdf问题

    pdfjs是一个js库,可以将pdf文件用canvas重新绘制,从而无需借助pdf读取插件就可以直接预览。 目前chrome内核的浏览器已内置pdf读取插件,但ie浏览器还没有。而我们最近在做的一个项目使用对象是医院,使用的浏览器竟然还是ie。所以我们只能把项目用js重写(当然也可以用j

    2024年02月07日
    浏览(33)
  • java实现pdf文件添加水印,下载到浏览器

    添加itextpdf依赖 根据需求,不需要指定路径可以删除对应的输出流 效果如下:代码中的相对路径在src平级目录下,test.pdf是PdfStamper里面fileOutputStream生成的,test1.pdf是fos生成的 浏览器下载的如下: 生成的pdf内容如下(红框里面是pdf原来的内容,可以自己调整代码中注释掉的设

    2024年02月05日
    浏览(45)
  • 在uniapp Vue3版本中如何解决web/H5网页浏览器跨域的问题

    uniapp项目在浏览器运行,有可能调用某些接口会出现跨域问题,报错如下图所示: 存在跨域问题的原因是因为浏览器的同源策略,也就是说前端无法直接发起跨域请求。同源策略是一个基础的安全策略,但是这也会给uniapp/Vue开发者在部署时带来一定的麻烦。一般来说,浏览

    2024年01月21日
    浏览(37)
  • web浏览器在线预览Excel,PDF,world文档解决方案

    众所周知啊,在web浏览器中是无法直接预览Excel、world文档等文件的,PDF有的浏览器是打开预览,有的浏览器是跳转到下载页,行为不一致也是让开发者头疼的事情。 今天给大家提供一个解决方案,实现office文件在线预览的解决方案,这个在开发OA,推送通知触达的应用非常有

    2024年02月17日
    浏览(47)
  • vue3 实现预览pdf的几种方式(vue3-pdf, iframe流展示,vue-office/pdf)

    功能描述: 要实现菜单(二级)绑定文件,并进行预览(点击菜单即触发),支持文件上传下载(绑定菜单),文件以byte[]形式保存到数据库(至于为什么不用文件存储系统,因为这是领导定的 =,= 而且这个功能比较小,数据也不多,成本有限),同时,要解析pdf文件里的内

    2024年02月16日
    浏览(37)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包