Vue項目中使用canvas和pdf.js預覽pdf檔案流
網上目前的解決方案大多是在将pdf.js放在static檔案内,這樣j6angjin的後果就是打封包件變得非常大(我的項目由800k變大到将近5m),後來發現了pdf.js的node包pdf_dist這個給我們提供了一個新的方向,使用npm安裝避免了打封包件過大的問題。
代碼實作
<template>
<div>
<canvas v-for="page in pages" :id="'the-canvas'+page" :key="page"></canvas>
</div>
</template>
<script>
import service from '@api/main'
import PDF from "pdfjs-dist";
import {
staticUrl
} from '@utils/config'
export default {
data() {
return {
PDFData:null,
pages: null
};
},
mounted() {
let url=this.$route.query.url
//ajax請求擷取檔案流,可根據自己需要修改
service.getPdfUrl(url).then(
data=>{
this.PDFData = data
let pdfurl=this.getObjectURL(this.PDFData)
this._loadFile(pdfurl);
}
)
},
components: {},
methods: {
//根據檔案流擷取url位址(使用blob)
getObjectURL(data) {
let blob = new Blob([data], {type: 'application/vnd.ms-excel;charset=utf-8'});//檔案流轉為blob
let url = window.URL.createObjectURL(blob); //建立下載下傳的連結
return url
},
//加載PDF
_loadFile(url) {
PDF.getDocument(url).then(pdf => {
this.pdfDoc = pdf;
this.pages = this.pdfDoc.numPages;
this.$nextTick(() => {
this._renderPage(1);//渲染第一頁PDF
});
});
},
//渲染PDF
_renderPage(num) {
this.pdfDoc.getPage(num).then(page => {
let canvas = document.getElementById("the-canvas" + num); //canvas畫布作為PDF展示容器~~
let ctx = canvas.getContext("2d");
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(
screen.availWidth / page.getViewport(1).width
);
canvas.width = viewport.width * ratio;
canvas.height = viewport.height * ratio;
canvas.style.width = viewport.width + "px";
canvas.style.height = viewport.height + "px";
ctx.setTransform(ratio, 0, 0, ratio, 0, 0);
let renderContext = {
canvasContext: ctx,
viewport: viewport
};
page.render(renderContext);
if (this.pages > num) {
this._renderPage(num + 1);//如pdf有多頁,則多次渲染
}
});
}
}
};
</script>
注意事項
vue中引入pdfjs依賴
npm install pdfjs-dist --save
擷取檔案流的請求需要添加responseType: ‘blob’,
const Axios = axios.create({
baseURL: baseURL,
responseType: 'blob',
headers: {
'Content-Type': 'application/x-www-form-urlencoded;charse