0


前端 PDF 预览技巧:标签 vs 插件,如何优雅地展示 PDF 文件

前言

pdf 作为一种常用的文档格式,相信很多同学都在项目中遇到过需要预览 pdf 文件的情况。其实实现的方式有很多,包括传统的标签 iframeembed 方式,也可以运用一些插件,例如 pdf.jsvue-pdf 等等,本文将带大家一起探索不同方式的优劣势以及实现方式和应用场景,帮助你更好地选择适合自己项目的方案,让你在项目中轻松展示 pdf 文件。


一、iframe 标签

<iframe>

标签规定一个内联框架。一个内联框架被用来在当前

HTML

文档中嵌入另一个文档。

1.1 属性

属性描述src在 iframe 中显示的文档的 URL。heightiframe 的高度。widthiframe 的宽度。nameiframe 的名称。seamlessiframe 看起来像是父文档中的一部分。srcdoc规定页面中的 HTML 内容显示在 iframe 中。sandbox对 iframe 的内容定义一系列额外的限制。allow-forms(允许在iframe中提交表单)、allow-same-origin(允许iframe与包含它的页面具有相同的源,这意味着它可以访问与包含页面相同的资源)、allow-scripts(允许在iframe中执行脚本)、allow-top-navigation(允许iframe导航到顶级浏览上下文,即顶级窗口)scrollingHTML5 不支持。规定是否在 iframe 中显示滚动条。yes、no、autoalignHTML5 不支持。HTML 4.01 已废弃。 规定如何根据周围的元素来对齐iframe。left、right、top、middle、bottomframeborder-HTML5 不支持。规定是否显示 iframe 周围的边框。longdescHTML5 不支持。规定一个页面,该页面包含了有关 iframe 的较长描述。marginheightHTML5 不支持。规定 iframe 的顶部和底部的边距marginwidthHTML5 不支持。规定 iframe 的左侧和右侧的边距。

1.2 代码实现

<template><div><iframesrc="https://s4.aconvert.com/convert/p3r68-cdx67/agb6w-9i4xt.pdf"width="100%"height="700"/></div></template>

实现效果

在这里插入图片描述


二、embed 标签

<embed>

标签定义了一个容器,用来嵌入外部应用或者互动程序(插件)。

2.1 属性

属性描述height规定嵌入内容的高度。src规定被嵌入内容的 URL。type规定嵌入内容的 MIME 类型。注:MIME = Multipurpose Internet Mail Extensions。width规定嵌入内容的宽度。

2.2 代码实现

<template><div><embedsrc="https://s4.aconvert.com/convert/p3r68-cdx67/abeub-nb503.pdf"type="application/pdf"width="100%"height="700"/></div></template>

实现效果

在这里插入图片描述


小结

使用

<embed>

<iframe>

标签浏览器会自动调用内置的PDF阅读器插件来显示

pdf

内容。相对于使用插件来显示

pdf

文件有各自的优劣势。

优势:

  • 简单易用: 使用 <embed><iframe> 标签可以很容易地嵌入 pdf 文件,而且不需要额外的插件或库;
  • 跨平台兼容性: <embed><iframe> 标签通常具有很好的跨平台兼容性,可以在各种浏览器和设备上正常显示 pdf 文件;
  • 快速集成: 直接使用标签嵌入 pdf 文件可以快速集成到现有的网页中,不需要额外的学习成本。

劣势:

  • 定制性差: 使用 <embed><iframe> 标签显示 pdf文件的定制性相对较差,无法轻松实现一些高级功能,如自定义样式、交互等;
  • 功能受限: <embed><iframe> 标签提供的功能有限,无法实现一些复杂的 pdf 显示需求,如搜索、缩略图预览、无法禁止打印等;
  • 样式控制困难: 使用 <embed><iframe> 标签嵌入的 pdf文件样式控制相对困难,难以实现与网页样式的统一。

三、vue-pdf 插件

vue-pdf 是一个基于

pdf.js

实现用于在

vue

应用程序中显示

pdf

文件的库。它提供了一个

vue

组件,可以轻松地将

pdf

文件嵌入到你的应用程序中,以便用户可以查看和与

pdf

文件交互。

3.1 安装

npm install --save vue-pdf

如果有版本问题可以降低版本,推荐安装以下版本:

npm install --save [email protected]

3.2 引入注册

  • 局部import pdf from"vue-pdf";exportdefault{components:{ pdf,},};
  • 全局import pdf from'vue-pdf';Vue.component('pdf', pdf);

3.3 常用的属性及事件

  • Props 属性属性描述:srcPDF 文件的 URL。:page要显示的页码。:rotate页面旋转的角度,仅限90度的倍数。 例如:90, 180, 270, 360, …
  • Events 事件事件描述@password (updatePassword, reason)updatePassword: 调用以输入 PDF 密码的函数。reason: 函数调用的原因,可能是 ‘NEED_PASSWORD’ 或 ‘INCORRECT_PASSWORD’@progress Number文档加载进度,范围从 0 到 1。@loaded文档加载完成时触发。@page-loaded Number页面加载完成后触发。@num-pages NumberPDF 的总页数。@error Object发生错误时触发。@link-clicked Number点击内部链接时触发。

3.4 基础使用(单页)

<template><pdfsrc="https://s4.aconvert.com/convert/p3r68-cdx67/a0jo0-a0e3v.pdf"></pdf></template><script>import pdf from"vue-pdf";exportdefault{components:{
    pdf,},};</script>

实现效果

在这里插入图片描述


3.5 加载本地pdf文件

如果直接将

pdf

文件放在任意一个文件夹中因为路径问题会加载不出来。所以需要将

pdf

放在

public > static

下(如下图),并用

/static/xxx.pdf

的路径方式进行引用(

/

即已经代表

public

)。

在这里插入图片描述

代码示例

<template><pdfsrc="../../../static/ceshi.pdf"></pdf></template><script>import pdf from"vue-pdf";exportdefault{components:{
    pdf,},};</script>

实现效果

在这里插入图片描述


3.6 分页预览(多页)

<template><divid="document"><!-- 分页组件 --><divclass="component"v-show="schedule === 1"><div@click="pageWay('first')"class="headTail">首页</div><div@click="rotateWay('obey')"class="headTail"><el-tooltipclass="item"effect="dark"content="顺时针旋转"placement="top"><istyle="font-size: 18px"class="el-icon-refresh-right"></i></el-tooltip></div><div@click="pageWay('pre')"class="fluctuatePage":style="pageNumber === 1 ? 'cursor: not-allowed;' : ''">
        上一页
      </div><divclass="pagination"><inputv-model.number="pageNumber"type="number"class="inputNumber"@input="inputEvent()"/><span> / {{ pageValue }}</span></div><div@click="pageWay('next')"class="fluctuatePage":style="pageNumber === pageValue ? 'cursor: not-allowed;' : ''">
        下一页
      </div><div@click="rotateWay('contrary')"class="headTail"><el-tooltipclass="item"effect="dark"content="顺时针旋转"placement="top"><istyle="font-size: 18px"class="el-icon-refresh-left"></i></el-tooltip></div><div@click="pageWay('last')"class="headTail">尾页</div></div><!-- pdf 组件 --><divclass="pdfContent"><pdf:src="pdfUrl"ref="pdf"v-show="schedule === 1":rotate="pageRotate":page="pageNumber"@num-pages="pageValue = $event"@progress="schedule = $event"@page-loaded="pageNumber = $event"@loaded="loadPdfHandler"@link-clicked="pageNumber = $event"id="pdfID"></pdf></div><!-- loading 组件 --><divclass="progress"v-show="schedule !== 1"><el-progresstype="circle":width="60"color="#53a7ff":percentage="Math.floor(schedule * 100)"></el-progress><p>{{ loadingTxt }}</p></div></div></template><script>import pdf from"vue-pdf";exportdefault{components:{
    pdf,},data(){const loadingText ="加载文件中,文件较大请耐心等待...";return{remindText:{loading: loadingText,// 加载中提示语refresh:"若卡住不动,可刷新页面重新加载...",// 刷新提示语},loadingTxt: loadingText,// 初始加载提示语pageRotate:0,//旋转角度pageNumber:0,// 当前页数pageValue:0,// 总页数schedule:0,// 加载进度timerId:"",// 定时器 IDpdfUrl:"https://s4.aconvert.com/convert/p3r68-cdx67/a2mdb-i5v70.pdf",// pdf 文件路径};},// 在组件销毁时清除定时器destroyed(){clearInterval(this.timerId);},mounted(){this.prohibit();this.timerId =setInterval(()=>{// 设置定时器,每隔一段时间切换加载提示语this.loadingTxt ===this.remindText.refresh
        ?(this.loadingTxt =this.remindText.loading):(this.loadingTxt =this.remindText.refresh);},4000);this.listenerFunction();// 调用监听滚动条事件的方法},methods:{// 监听输入事件inputEvent(){// 输入页数大于总页数时,设置为总页数,输入页数小于 1 时,设置为 1this.pageNumber = Math.max(1, Math.min(this.pageNumber,this.pageValue));},// 上一页、下一页、首页、尾页事件pageWay(val){if(val ==="pre"&&this.pageNumber >1){this.pageNumber--;// 上一页}elseif(val ==="next"&&this.pageNumber <this.pageValue){this.pageNumber++;// 下一页}elseif(val ==="first"){this.pageNumber =1;// 首页}elseif(val ==="last"&&this.pageNumber <this.pageValue){this.pageNumber =this.pageValue;// 尾页}this.toTop();// 滚动到顶部},// 顺/逆旋转rotateWay(val){this.pageRotate += val ==="obey"?90:-90;},// 滚动顶部toTop(){const container = document.getElementById("document").parentElement;
      container.scrollIntoView({behavior:"smooth",block:"start"});},// 监听 pdf 加载完成事件loadPdfHandler(){this.pageNumber =1;// 加载 pdf 时,设置当前页数为 1},// 禁止特定的操作prohibit(){// 禁用右键菜单
      document.oncontextmenu=function(){returnfalse;};// 禁用按键
      document.onkeydown=function(e){// 定义需要禁用的按键码数组const forbiddenKeys =[65,67,73,74,80,83,85,86,117,18,123];// 判断按下的按键是否在禁用数组中,如果是则返回 false 禁用按键if(e.ctrlKey && forbiddenKeys.includes(e.keyCode)){returnfalse;}};},// 监听滚动条事件listenerFunction(e){
      document
        .getElementById("document").addEventListener("scroll",function(event){// 监听滚动事件
          console.log(event);});},},};</script><stylescopedlang="less">#document{overflow: auto;min-height: 100vh;width: 100%;display: flex;position: relative;.component{user-select: none;color: #ffffff;position: fixed;bottom: 5%;left: 50%;margin-left: -250px;display: flex;align-items: center;justify-content: space-around;background:rgba(0, 0, 0, 0.7);border-radius: 30px;width: 420px;padding: 15px 40px;z-index: 99;.pagination{position: relative;top: 1px;.inputNumber{border-radius: 5px;border: 1px solid #8b8b8b;width: 36px;height: 16px;text-align: center;background: transparent;}.inputNumber:focus{border: 1px solid #00aeff;background:rgba(18, 163, 230, 0.1);outline: none;transition: 0.2s;}}.headTail{border-radius: 50%;display: flex;align-items: center;justify-content: center;}.fluctuatePage{border-radius: 50%;display: flex;align-items: center;justify-content: center;}.fluctuatePage:hover,
    .headTail:hover{transition: 0.3s;color: #409eff;cursor: pointer;}}.pdfContent{width: 100%;}.progress{width: 222px;position: absolute;top: 50%;left: 50%;margin-left: -111px;text-align: center;}.progress p{color: #199edb;font-size: 14px;}}/*在谷歌下移除input[number]的上下箭头*/input::-webkit-outer-spin-button,
input::-webkit-inner-spin-button{-webkit-appearance: none !important;margin: 0;}/*在firefox下移除input[number]的上下箭头*/input[type="number"]{-moz-appearance: textfield;}</style>

实现效果

在这里插入图片描述


3.7 打印文件

vue-pdf

中,

print(dpi, pageList)

方法用于触发打印

pdf

文件的功能。

  • dpi:表示打印的分辨率(每英寸的点数)。这个参数用于设置打印时的图像质量,通常可以设置为一个整数值,例如 150300 等。较高的 dpi 值会产生更清晰的打印效果,但也会增加打印文件的大小。
  • pageList:表示要打印的页面列表。这个参数是一个数组,用于指定要打印的页面序号。例如,如果你想打印第 1 页和第 3 页,可以将 pageList 设置为 [1, 3]。如果想打印所有页面,可以使用类似于 [1, 2, 3, ...] 的方式来表示所有页面。
// 设置打印分辨率为 150dpi,打印第1页和第3页this.$refs.myPdfComponent.print(150,[1,3]);
<template><div><button@click="printPdf">打印 pdf</button><pdfref="myPdfComponent":src="pdfSrc"></pdf></div></template><script>import pdf from"vue-pdf";exportdefault{components:{
    pdf,},data(){return{pdfSrc:"https://s4.aconvert.com/convert/p3r68-cdx67/a1eqq-4rahm.pdf",};},};</script>

实现效果

在这里插入图片描述


3.8 加密文件

如果你的

pdf

文件是加密的,那么就可以调用

password

方法。

  • updatePassword这个函数用于更新 pdf 文件的密码。当用户输入了正确的密码后,可以调用 updatePassword 函数来更新 pdf 文件的密码。
  • reason这是一个字符串,表示需要密码的原因。通常会包含一些提示信息,告诉用户为什么需要输入密码才能查看 pdf 文件。
<template><pdf:src="pdfUrl"@password="handlePassword"/></template><script>import pdf from"vue-pdf";exportdefault{components:{
    pdf,},data(){return{pdfUrl:"https://s4.aconvert.com/convert/p3r68-cdx67/a9tag-qf2jw.pdf",};},methods:{handlePassword(updatePassword, reason){if(reason ==="NEED_PASSWORD"){// 这里可以提示用户输入密码,然后使用输入的密码来更新PDF文档let password =prompt("请输入PDF文档的密码:","");updatePassword(password);}},},};</script>

实现效果

在这里插入图片描述


3.9 无法显示中文内容

一般情况下,是不会出现显示不了中文的问题。但不排除一些特殊的文档,例如票据、合同这类。

<template><pdf:src="pdfUrl"/></template><script>import pdf from"vue-pdf";exportdefault{components:{
    pdf,},data(){return{pdfUrl:"",};},methods:{getPdfPort(){// 解析 PDFconst taskData = pdf.createLoadingTask({url: res.data,cMapUrl:"https://cdn.jsdelivr.net/npm/[email protected]/cmaps/",cMapPacked:true,});// 把解析后的地址进行赋值this.pdfUrl = taskData;},},};</script>

上面代码通过

pdf.createLoadingTask()

方法创建一个任务,该任务负责加载和解析指定的

pdf

文件。通过这个方法,可以异步地加载

pdf

文件并获取解析后的数据,以便在页面中显示

pdf

内容。

  • pdf.createLoadingTask() 方法参数参数描述url要加载的 pdf 文件的 url。cMapUrl字符映射文件的 url,用于将 pdf 文件中的字符编码映射到可显示的字符。cMapPacked布尔值,指示是否使用压缩的字符映射文件。

拓展

后台返回文档流

很多时候,考虑到安全性、实时性,后台可能不一定会直接返回一个

url

链接,而是会返回一个流文件(如下图所示),这个时候就需要对原始的流文件进行处理后再进行赋值。

在这里插入图片描述

实现代码

<template><div><button@click="pdfWay">预览pdf</button><iframe:src="item.iframeUrl"width="100%"height="550"/></div></template><script>exportdefault{data(){return{iframeUrl:"",};},methods:{pdfWay(){previewPort().then((res)=>{// 接口方法var binaryData =[];
        binaryData.push(res);this.iframeUrl = window.URL.createObjectURL(newBlob(binaryData,{type:"application/pdf"}));});},},};</script>

在上面的代码中,

new Blob(binaryData, { type: "application/pdf" })

会创建了一个

Blob

二进制对象,

binaryData

是一个包含

pdf

文件二进制数据的数组,

{ type: "application/pdf" }

指定了这个

Blob

对象的类型为

pdf

文件类型。然后我们调用了

createObjectURL()

方法,该方法接受一个

Blob

对象作为参数,并返回一个包含该

Blob

对象数据的

url

。这个

url

是一个临时的、唯一的

url

,可以用于在浏览器中直接访问和展示

Blob

对象的内容。通过这个

url

,我们就可以直接在页面上展示

pdf

文件的内容。

标签: 前端 vue

本文转载自: https://blog.csdn.net/Shids_/article/details/141401073
版权归原作者 水星记_ 所有, 如有侵权,请联系我们删除。

“前端 PDF 预览技巧:标签 vs 插件,如何优雅地展示 PDF 文件”的评论:

还没有评论