900字范文,内容丰富有趣,生活中的好帮手!
900字范文 > vue 项目中分别使用 vue-pdf 插件和内嵌 iframe 实现 PDF 文件预览 缩放 旋

vue 项目中分别使用 vue-pdf 插件和内嵌 iframe 实现 PDF 文件预览 缩放 旋

时间:2020-12-15 09:18:17

相关推荐

vue 项目中分别使用 vue-pdf 插件和内嵌 iframe 实现 PDF 文件预览 缩放 旋

需求:在 vue 和 element-ui项目中,有点击按钮预览,下载,打印 PDF文件需求,要求支持 PDF的预览,上下页切换,首尾页切换,页码选择跳转,放大缩小,顺时针逆时针旋转,下载,打印等功能 。

实现:方法一可以考虑使用vue-pdf 插件去实现;方法二考虑使用内嵌 iframe去实现,下面会对两种方法实现过程进行总结 。

对比:使用内嵌 iframe方法,实现简单,由于采用的是浏览器内部对于 PDF窗口的操作,导致在不同浏览器下,样式和功能控件不统一。使用 vue-pdf实现,可以做到样式和功能控件统一,需要解决控制台报错,打印中文乱码等问题 。

方法一:使用 vue-pdf插件实现

安装依赖

npm i --save vue-pdf// 或者cnpm i --save vue-pdf

组件页面中引入并注册

// 引入import pdf from "vue-pdf"export default{// 注册components: {pdf}}

单页使用案例(组件 pdf上只有 src属性时,默认只展示第一页)

<template><div class="main"><pdf :src="src"></pdf></div></template><script>// pdf预览import pdf from "vue-pdf";export default {name: "home",components: {pdf},data() {return {src:"/public_assets/xuetangx/PDF/PlayerAPI_v1.0.6.pdf"};}};</script><style scoped>.main {width: 500px;margin: 0 auto;border: 2px solid #409eff;padding: 10px;}</style>

多页使用案例(结合 element,支持 PDF预览,上下页切换,首尾页切换,页码选择跳转,放大缩小,顺时针和逆时针旋转,下载和打印等功能 )

<template><div><el-button type="primary" size="small" class="btn" @click="dialogVisible = true">{{btnText}}</el-button><el-dialog title="PDF 预览" :visible.sync="dialogVisible" :close-on-click-modal="false" width="500"><div class="tools"><el-button type="text" @click="FirstPage()"><el-tooltip class="item" effect="light" content="第一页" placement="top"><i class="el-icon-d-arrow-left"></i></el-tooltip></el-button><el-button type="text" @click="changePdfPage(0)"><el-tooltip class="item" effect="light" content="上一页" placement="top"><i class="el-icon-arrow-left"></i></el-tooltip></el-button><el-button type="text" @click="changePdfPage(1)"><el-tooltip class="item" effect="light" content="下一页" placement="top"><i class="el-icon-arrow-right"></i></el-tooltip></el-button><el-button type="text" @click="lastPage()"><el-tooltip class="item" effect="light" content="最后一页" placement="top"><i class="el-icon-d-arrow-right"></i></el-tooltip></el-button><el-button type="text" @click="setIsExit()" v-show="!isExit" style="margin-right:10px;"><el-tooltip class="item" effect="light" content="页码选择" placement="top"><i class="el-icon-setting"></i></el-tooltip></el-button><el-tooltip class="item" effect="light" content="页码选择" placement="top" v-show="isExit"><el-select v-model="value" placeholder="请选择" @change="pageSelect" size="mini"><el-option v-for="item in pageCount" :key="item" :label="'第 '+item+' 页'" :value="item"></el-option></el-select></el-tooltip><el-button type="text" @click="scaleD()"><el-tooltip class="item" effect="light" content="放大" placement="top"><i class="el-icon-zoom-in"></i></el-tooltip></el-button><el-button type="text" @click="scaleX()"><el-tooltip class="item" effect="light" content="缩小" placement="top"><i class="el-icon-zoom-out"></i></el-tooltip></el-button><el-button type="text" @click="clock()"><el-tooltip class="item" effect="light" content="顺时针旋转" placement="top"><i class="el-icon-refresh-right"></i></el-tooltip></el-button><el-button type="text" @click="counterClock()"><el-tooltip class="item" effect="light" content="逆时针旋转" placement="top"><i class="el-icon-refresh-left"></i></el-tooltip></el-button><el-button type="text" @click="downPDF"><el-tooltip class="item" effect="light" content="下载" placement="top"><i class="el-icon-download"></i></el-tooltip></el-button><el-button type="text" @click="printPDF"><el-tooltip class="item" effect="light" content="打印" placement="top"><i class="el-icon-printer"></i></el-tooltip></el-button><p class="total"><el-tooltip class="item" effect="light" content="当前页" placement="top"><b style="color:#F56C6C;cursor:pointer;">{{ currentPage }}</b> </el-tooltip>&nbsp;/&nbsp;<el-tooltip class="item" effect="light" content="总页数" placement="top"><b style="color:#67C23A;cursor:pointer;">{{ pageCount }}</b></el-tooltip></p></div><div class="main"><pdf ref="pdf" id="pdf" :src="src" :page="currentPage" :rotate="pageRotate" @num-pages="pageCount = $event" @page-loaded="currentPage = $event"@loaded="loadPdfHandler"></pdf></div></el-dialog></div></template><script>// 引入import pdf from 'vue-pdf'export default {name: 'home',// 注册components: {pdf},data() {return {dialogVisible: false,isExit: false,value: 1,btnText: 'PDF 预览 (vue-pdf 插件)',// 加载本地的 PDF 文件,要放在 public 目录下,访问路径如 '/test.pdf'//src: '/test.pdf',src: '/public_assets/xuetangx/PDF/PlayerAPI_v1.0.6.pdf',currentPage: 0, // pdf文件页码pageCount: 0, // pdf文件总页数scale: 100,pageRotate: 0}},methods: {// pdf加载时loadPdfHandler() {this.value = this.currentPage = 1 // 加载的时候先加载第一页},// 第一页FirstPage() {this.value = this.currentPage = 1this.isExit = false},// 最后一页lastPage() {this.value = this.currentPage = this.pageCountthis.isExit = false},// 改变PDF页码,val 传过来区分上一页下一页的值,0 上一页,1 下一页changePdfPage(val) {if (val === 0 && this.currentPage > 1) {this.currentPage--}if (val === 1 && this.currentPage < this.pageCount) {this.currentPage++}this.value = this.currentPagethis.isExit = false},// 页码选择pageSelect() {this.currentPage = this.valuethis.isExit = false},// 控制下拉选择框显示隐藏setIsExit() {this.isExit = true},// 放大scaleD() {this.scale += 5this.$refs.pdf.$el.style.width = parseInt(this.scale) + '%'},// 缩小scaleX() {if (this.scale === 100) {return}this.scale += -5this.$refs.pdf.$el.style.width = parseInt(this.scale) + '%'},// 顺时针clock() {this.pageRotate += 90},// 逆时针counterClock() {this.pageRotate -= 90},// 下载downPDF() {var url = this.srcvar tempLink = document.createElement('a')tempLink.style.display = 'none'tempLink.href = urltempLink.setAttribute('download', 'my.pdf')if (typeof tempLink.download === 'undefined') {tempLink.setAttribute('target', '_blank')}document.body.appendChild(tempLink)tempLink.click()document.body.removeChild(tempLink)},// 打印printPDF() {this.$refs.pdf.print()}}}</script><style scoped>.btn {margin: 20px 0px;}.main {border: 2px solid #dcdfe6;height: 600px;overflow: auto;}.tools {display: flex;}.total {width: 80px;display: flex;align-items: center;justify-content: center;}.main::-webkit-scrollbar {width: 6px;}/* 修改 滚动条的 下面 的 样式 */.main::-webkit-scrollbar-track {background-color: white;-webkit-border-radius: 2em;-moz-border-radius: 2em;border-radius: 2em;}/* 修改 滑块 */.main::-webkit-scrollbar-thumb {background-color: #dcdfe6;-webkit-border-radius: 2em;-moz-border-radius: 2em;border-radius: 2em;}/deep/ .el-dialog {height: 735px;font-family: '楷体';}/deep/ .el-dialog__header {display: flex;justify-content: space-between;align-items: center;background: #303133;}/deep/ .el-dialog__title,/deep/ .el-dialog__headerbtn .el-dialog__close {color: white;}/deep/ .el-dialog__body {padding: 20px;}/deep/ .el-select {width: 95px;height: 28px;margin: 5px 20px 0px 20px;}</style>

报错解决(更改依赖包 node_modules/vue-pdf/src/pdfjsWrapper.js 文件)

注意:解决顺时针,逆时针旋转控制台报错;打印时,文字乱码等问题。通过更改依赖包 node_modules/vue-pdf/src/pdfjsWrapper.js 文件解决。下面为修改好的 pdfjsWrapper的文件 。

import {PDFLinkService} from 'pdfjs-dist/es5/web/pdf_viewer';var pendingOperation = Promise.resolve();export default function (PDFJS) {function isPDFDocumentLoadingTask(obj) {return typeof (obj) === 'object' && obj !== null && obj.__PDFDocumentLoadingTask === true;// or: return obj.constructor.name === 'PDFDocumentLoadingTask';}function createLoadingTask(src, options) {var source;if (typeof (src) === 'string')source = { url: src };else if (src instanceof Uint8Array)source = {data: src};else if (typeof (src) === 'object' && src !== null)source = Object.assign({}, src);elsethrow new TypeError('invalid src type');// source.verbosity = PDFJS.VerbosityLevel.INFOS;// source.pdfBug = true;// source.stopAtErrors = true;if (options && options.withCredentials)source.withCredentials = options.withCredentials;var loadingTask = PDFJS.getDocument(source);loadingTask.__PDFDocumentLoadingTask = true; // since PDFDocumentLoadingTask is not publicif (options && options.onPassword)loadingTask.onPassword = options.onPassword;if (options && options.onProgress)loadingTask.onProgress = options.onProgress;return loadingTask;}function PDFJSWrapper(canvasElt, annotationLayerElt, emitEvent) {var pdfDoc = null;var pdfPage = null;var pdfRender = null;var canceling = false;canvasElt.getContext('2d').save();function clearCanvas() {canvasElt.getContext('2d').clearRect(0, 0, canvasElt.width, canvasElt.height);}function clearAnnotations() {while (annotationLayerElt.firstChild)annotationLayerElt.removeChild(annotationLayerElt.firstChild);}this.destroy = function () {if (pdfDoc === null)return;// Aborts all network requests and destroys worker.pendingOperation = pdfDoc.destroy();pdfDoc = null;}this.getResolutionScale = function () {return canvasElt.offsetWidth / canvasElt.width;}this.printPage = function (dpi, pageNumberOnly) {if (pdfPage === null)return;// 1in == 72pt// 1in == 96pxvar PRINT_RESOLUTION = dpi === undefined ? 150 : dpi;var PRINT_UNITS = PRINT_RESOLUTION / 72.0;var CSS_UNITS = 96.0 / 72.0;var printContainerElement = document.createElement('div');printContainerElement.setAttribute('id', 'print-container')function removePrintContainer() {printContainerElement.parentNode.removeChild(printContainerElement);}new Promise(function (resolve, reject) {printContainerElement.frameBorder = '0';printContainerElement.scrolling = 'no';printContainerElement.width = '0px;'printContainerElement.height = '0px;'printContainerElement.style.cssText = 'position: absolute; top: 0; left: 0';window.document.body.appendChild(printContainerElement);resolve(window)}).then(function (win) {win.document.title = '';return pdfDoc.getPage(1).then(function (page) {var viewport = page.getViewport({scale: 1});printContainerElement.appendChild(win.document.createElement('style')).textContent ='@supports ((size:A4) and (size:1pt 1pt)) {' +'@page { margin: 1pt; size: ' + ((viewport.width * PRINT_UNITS) / CSS_UNITS) + 'pt ' + ((viewport.height * PRINT_UNITS) / CSS_UNITS) + 'pt; }' +'}' +'#print-canvas { display: none }' +'@media print {' +'body { margin: 0 }' +'#print-canvas { page-break-before: avoid; page-break-after: always; page-break-inside: avoid; display: block }' +'body > *:not(#print-container) { display: none; }' +'}' +'@media screen {' +'body { margin: 0 }' +'}'return win;})}).then(function (win) {var allPages = [];for (var pageNumber = 1; pageNumber <= pdfDoc.numPages; ++pageNumber) {if (pageNumberOnly !== undefined && pageNumberOnly.indexOf(pageNumber) === -1)continue;allPages.push(pdfDoc.getPage(pageNumber).then(function (page) {var viewport = page.getViewport({scale: 1});var printCanvasElt = printContainerElement.appendChild(win.document.createElement('canvas'));printCanvasElt.setAttribute('id', 'print-canvas')printCanvasElt.width = (viewport.width * PRINT_UNITS);printCanvasElt.height = (viewport.height * PRINT_UNITS);return page.render({canvasContext: printCanvasElt.getContext('2d'),transform: [ // Additional transform, applied just before viewport transform.PRINT_UNITS, 0, 0,PRINT_UNITS, 0, 0],viewport: viewport,intent: 'print'}).promise;}));}Promise.all(allPages).then(function () {win.focus(); // Required for IEif (win.document.queryCommandSupported('print')) {win.document.execCommand('print', false, null);} else {win.print();}removePrintContainer();}).catch(function (err) {removePrintContainer();emitEvent('error', err);})})}this.renderPage = function (rotate) {if (pdfRender !== null) {if (canceling)return;canceling = true;pdfRender.cancel();// pdfRender.cancel().catch(function (err) {// emitEvent('error', err);// });return;}if (pdfPage === null)return;var pageRotate = (pdfPage.rotate === undefined ? 0 : pdfPage.rotate) + (rotate === undefined ? 0 : rotate);var scale = canvasElt.offsetWidth / pdfPage.getViewport({scale: 1}).width * (window.devicePixelRatio || 1);var viewport = pdfPage.getViewport({scale: scale,rotation: pageRotate});emitEvent('page-size', viewport.width, viewport.height, scale);canvasElt.width = viewport.width;canvasElt.height = viewport.height;pdfRender = pdfPage.render({canvasContext: canvasElt.getContext('2d'),viewport: viewport});annotationLayerElt.style.visibility = 'hidden';clearAnnotations();var viewer = {scrollPageIntoView: function (params) {emitEvent('link-clicked', params.pageNumber)},};var linkService = new PDFLinkService();linkService.setDocument(pdfDoc);linkService.setViewer(viewer);pendingOperation = pendingOperation.then(function () {var getAnnotationsOperation =pdfPage.getAnnotations({intent: 'display'}).then(function (annotations) {PDFJS.AnnotationLayer.render({viewport: viewport.clone({dontFlip: true}),div: annotationLayerElt,annotations: annotations,page: pdfPage,linkService: linkService,renderInteractiveForms: false});});var pdfRenderOperation =pdfRender.promise.then(function () {annotationLayerElt.style.visibility = '';canceling = false;pdfRender = null;}).catch(function (err) {pdfRender = null;if (err instanceof PDFJS.RenderingCancelledException) {canceling = false;this.renderPage(rotate);return;}emitEvent('error', err);}.bind(this))return Promise.all([getAnnotationsOperation, pdfRenderOperation]);}.bind(this));}this.forEachPage = function (pageCallback) {var numPages = pdfDoc.numPages;(function next(pageNum) {pdfDoc.getPage(pageNum).then(pageCallback).then(function () {if (++pageNum <= numPages)next(pageNum);})})(1);}this.loadPage = function (pageNumber, rotate) {pdfPage = null;if (pdfDoc === null)return;pendingOperation = pendingOperation.then(function () {return pdfDoc.getPage(pageNumber);}).then(function (page) {pdfPage = page;this.renderPage(rotate);emitEvent('page-loaded', page.pageNumber);}.bind(this)).catch(function (err) {clearCanvas();clearAnnotations();emitEvent('error', err);});}this.loadDocument = function (src) {pdfDoc = null;pdfPage = null;emitEvent('num-pages', undefined);if (!src) {canvasElt.removeAttribute('width');canvasElt.removeAttribute('height');clearAnnotations();return;}// wait for pending operation endspendingOperation = pendingOperation.then(function () {var loadingTask;if (isPDFDocumentLoadingTask(src)) {if (src.destroyed) {emitEvent('error', new Error('loadingTask has been destroyed'));return}loadingTask = src;} else {loadingTask = createLoadingTask(src, {onPassword: function (updatePassword, reason) {var reasonStr;switch (reason) {case PDFJS.PasswordResponses.NEED_PASSWORD:reasonStr = 'NEED_PASSWORD';break;case PDFJS.PasswordResponses.INCORRECT_PASSWORD:reasonStr = 'INCORRECT_PASSWORD';break;}emitEvent('password', updatePassword, reasonStr);},onProgress: function (status) {var ratio = status.loaded / status.total;emitEvent('progress', Math.min(ratio, 1));}});}return loadingTask.promise;}).then(function (pdf) {pdfDoc = pdf;emitEvent('num-pages', pdf.numPages);emitEvent('loaded');}).catch(function (err) {clearCanvas();clearAnnotations();emitEvent('error', err);})}annotationLayerElt.style.transformOrigin = '0 0';}return {createLoadingTask: createLoadingTask,PDFJSWrapper: PDFJSWrapper,}}

方法二:内嵌 iframe实现

具体示例

<template><div><!-- 控制浮层显示隐藏 --><el-button type="primary" size="small" class="btn" @click="dialogVisible = true">{{btnText}}</el-button><!-- 浮层显示区域 --><el-dialog title="PDF 预览" :visible.sync="dialogVisible" :close-on-click-modal="false"><!-- PDF 展示区域 --><div class="main"><iframe id="printIframe" :src="src" frameborder="0" style="width:100%;height:100%;"></iframe></div></el-dialog></div></template><script>export default {name: 'ViewPDF',data() {return {dialogVisible: false,btnText: 'PDF 预览 (内嵌 iframe)',src: '/public_assets/xuetangx/PDF/PlayerAPI_v1.0.6.pdf'}}}</script><style lang="css" scoped>.btn {margin: 20px 0px;}.main {height: 700px;overflow: hidden;}/deep/ .el-dialog {width: 1000px;height: 700px;font-family: '楷体';}/deep/ .el-dialog__header {display: flex;justify-content: space-between;align-items: center;}/deep/ .el-dialog__body {padding: 0;}</style>

【完整示例查看:vue-pdf: VUE 中使用 vue-pdf 插件和 iframe 实现PDF的预览,上下页切换,首尾页切换,页码选择跳转,放大缩小,顺时针逆时针旋转,下载,打印等功能 。】

vue 项目中分别使用 vue-pdf 插件和内嵌 iframe 实现 PDF 文件预览 缩放 旋转 下载 保存等功能 ?

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。