PC端
直接使用iframe嵌套即可
<iframe
class="course-file-iframe"
:src="url"
></iframe>
url就是pdf的线上文档地址
不过我们项目后端并不给返回地址,只返回一个key 然后让前端用这个key去走下载链接来下载这个文件,因此我这里是请求blob二进制流文件,相当于存储到当前浏览器中,然后展示
request.get(apis.url.fileDownload, {
params: {key: fileKey},
// 请求类型为blob格式的二进制文件流
responseType: 'blob',
}).then(res => {
// 获取到的blob类型文件地址 pdf文件对应的MIME类型为'application/pdf'
let type = 'application/pdf';
const blob = new Blob([res], {type});
// 这就是blob类型文件地址 赋值给src即可展示(仅限PC端)
this.url = window.URL.createObjectURL(blob);
}).catch(err => {
console.error('文件获取失败', err);
});
H5端
h5端 用iframe 展示pdf的话 会提示 no enabled plugin supports this MIME type
因此 h5端只能引入第三方插件实现
方案一:vue-pdf
优点:代码少 写的快
缺点:
1. 是以canvas画出来的图片实现的 因此文件中的链接无法点击 (目前我没能解决)
2. 页面能渲染出来,就是控制台报错 没有catch这个属性 (切换版本解决 npm i vue-pdf@4.2.0)
3. 好像说是还有什么付费字体无法展示之类的,我没有遇到,可能需要各位自己遇到的时候自己找了
<div
v-else-if="isLocalFile"
class="course-file-iframe"
>
<pdf
v-for="index in numPages"
:key="index"
:src="pdfUrl"
:page="index"
/>
</div>
import Pdf from 'vue-pdf';
export default {
components: {
Pdf
},
data() {
return {
numPages: null,
pdfUrl: '',
}
},
methods: {
// 请求pdf文件地址的方法,每个人每个项目都不一样, 按自己的来
getUrl() {
request.get(api.fileGeneralDownload, {
params: {key: fileKey},
responseType: 'blob',
}).then(res => {
let type = 'application/pdf';
const blob = new Blob([res], {type});
this.videoUrl = window.URL.createObjectURL(blob);
this.loadPdf();
}).catch(err => {
console.error('文件获取失败', err);
});
},
// 上下滚动pdf加载
loadPdf() {
this.pdfUrl = Pdf.createLoadingTask(this.videoUrl);
this.pdfUrl.promise.then(pdf => {
this.$nextTick(() => {
this.numPages = pdf.numPages; // pdf总页数
});
});
},
}
}
<style lang="less" scoped>
.course-file-iframe {
width: 100%;
height: calc(100% - 45px);
border: none;
overflow: auto;
}
</style>
方案二:pdfjs-dist
缺点:
1. 也是以canvas画出来的图片实现的 因此文件中的链接无法点击 (目前我没能解决)
2. 好像也说是还有什么付费字体无法展示之类的,我没有遇到,可能需要各位自己遇到的时候自己找了
<div class="course-file-iframe">
<canvas
v-for="page in pages"
:id="'the-canvas' + page"
:key="page"
></canvas>
</div>
const PDFJS = require('pdfjs-dist');
PDFJS.GlobalWorkerOptions.workerSrc = require('pdfjs-dist/build/pdf.worker.min');
export default {
data() {
return {
pdfDoc: null,
pages: 0,
pdfUrl: '',
src: '',
loadding: true,
file: true,
isDestory: true
}
},
methods: {
// 请求pdf文件地址的方法,每个人每个项目都不一样, 按自己的来
getUrl() {
request.get(api.fileGeneralDownload, {
params: {key: fileKey},
responseType: 'blob',
}).then(res => {
let type = 'application/pdf';
const blob = new Blob([res], {type});
this.videoUrl = window.URL.createObjectURL(blob);
this.loadFile(this.videoUrl);
}).catch(err => {
console.error('文件获取失败', err);
});
},
renderPage(num) {
// getPage 处理每个页面
// 返回单页内容实例(页面引索) pdf.getPage(index)
this.pdfDoc.getPage(num).then(page => {
// canvas 绘制 PDF
let canvas = document.getElementById('the-canvas' + num)
let ctx = canvas.getContext('2d');
ctx.mozImageSmoothingEnabled = false;
ctx.webkitImageSmoothingEnabled = false;
ctx.msImageSmoothingEnabled = false;
ctx.imageSmoothingEnabled = false;
let dpr = window.devicePixelRatio || 1;
let bsr = ctx.webkitBackingStorePixelRatio
|| ctx.mozBackingStorePixelRatio
|| ctx.msBackingStorePixelRatio
|| ctx.oBackingStorePixelRatio
|| ctx.backingStorePixelRatio
|| 1;
let ratio = dpr / bsr;
// 这里我一直没有获取到宽高 百度了很多都不对 最后才发现是传参的问题 具体分析看下面的遇到的坑
let viewport = page.getViewport(1);
canvas.width = viewport.width * ratio;
canvas.height = viewport.height * ratio;
canvas.style.width = '100%';
canvas.style.height = 'calc(100% - 50px)';
let renderContext = {
canvasContext: ctx,
viewport: viewport,
transform: [ratio, 0, 0, ratio, 0, 0]
};
const that = this;
page.render(renderContext).promise.then(() => {
if (that.isDestory) {
if (that.pages > num) {
that.renderPage(num + 1);
}
}
});
});
},
loadFile(url) {
PDFJS.getDocument(url).promise.then(pdf => {
this.pdfDoc = pdf;
this.pages = this.pdfDoc.numPages;
this.loadding = false;
const that = this;
if (that.isDestory) {
this.$nextTick(() => {
this.renderPage(1);
});
}
}).catch(err => {
console.log('err', err);
});
},
}
}
遇到的坑
pdfjs-dist 我getViewport 一直拿不到宽高 NaN (我的版本号就是2.0.943)
网上说改版本号啥的 都不对
最后我看了看node_module里的源码才发现传参错了
他只有一个形参 scale。 并不是github里 issue里说的 那样有三个参数或者是个对象
高版本的可能需要自己看一下源码,2.0.943 版本的只用穿一个scale就行了 ,像我之前传的是一个对象的话 就会导致 pdf倒置 且拿不到宽高 ,改成一个值之后 就正常展示了