1.使用npm下載兩個插件
a.將html頁面轉換成圖片 npm install --save html2canvas b.將圖片生成pdf npm install jspdf --save
或者直接使用cdn
<script src="https://cdnjs.cloudflare.com/ajax/libs/html2canvas/0.5.0-alpha1/html2canvas.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/jspdf/1.3.4/jspdf.min.js"></script>
html部分

<template> <div class=""> <div @click="downLoadPdf">下載pdf文件</div> <!-- --> <button type="button" class="btn btn-primary" v-on:click="getPdf()">導出PDF分頁</button> <div class="pdf_warp"> <div id="pdfDom"> <h1>vue項目中使用pdf.js預覽pdf文件(流)</h1> <p class=""> 好一段時間沒有來簡書寫東西了,因為來到了平安銀行(橙信)工作了,工作也比較忙,上班也沒得外網,最近公司給配置了一個mac電腦,終於可以有外網權限了,但還是有很多限制,微信,百度雲盤等等吧,都用不了, 最近項目中需要顯示保險的電子保單,但給的地址是一個pdf文件流,遇到了各種問題,跨域、android手機打不開......,最終選擇了pdf.js插件,viewer.html?file=的形式打開,下面詳情介紹一下開發步驟, </p> <p>一、 首先是導入插件,從官網直接下載,鏈接:官網直接下載,在vue項目中,注意放在static文件目錄下</p> <div class="img_warp"> <img src="../../../assets/4369687-c90a77c68fc6e04a.webp" alt=""> </div> <p>簡單介紹一下pdf.js目錄,核心的pdf.js和pdf.worker.js,以及展示pdf的viewer.html頁面,把它們作為靜態資源來編譯,基本想要的build和web這兩個重要文件夾的東西都正常編譯。</p> <p>二、重點介紹一下viewer.html?file=打開pdf文件</p> <p>1、打開viewer.js看看</p> <div class="js_warp"> <p>"use strict";</p> <p>var DEFAULT_URL = 'compressed.tracemonkey-pldi-09.pdf';</p> <p>var pdfjsWebApp = void 0;</p> </div> <p>里面有配置項,DEFAULT_URL 是默認的pdf路徑,繼續看源代碼,發現他可以通過file參數用來指定pdf的路徑</p> <p>用viewer.html?file= 的方式,我是iframe進行嵌套</p> <!-- <div class="js_warp"> <p><iframe :src="url" width="100%" height="100%"></iframe></p> </div> --> <p>2、當viewer.html頁面的域和pdf文件域不一致的時候,會報 “file origin does not match viewer”錯誤。 所以我們得改變一下源碼</p> <div class="img_warp"> <img src="../../../assets/cw1.webp" alt=""> </div> <p>3、file=后面跟的pdf地址也有參數,所以必須選擇 encodeURIComponent 進行對url的編碼</p> <div class="js_warp"> <p>this.url = `${baseUrl.pageRoot}pdf/web/viewer.html?file=${encodeURIComponent(pdfUrl)}`</p> </div> <p>viewer.js里有方法parseQueryString(query)取到這個pdf文件地址后,會進行decodeURIComponent解碼</p> <p>4、如果還是打不開pdf文件,pdf.js插件可能無法識別pdfUrl,所以的在最后加上 &.pdf 來騙過插件</p> <p>Q: 目前還遇到一個問題,GET請求pdfUrl時,cookie信息沒有帶給后端,目前是讓后端直接屏蔽了登錄驗證,請各位指教。GET請求源碼如下:</p> <h1>vue3基礎</h1> <h2>一、setup</h2> <p>1.setup函數可以被理解為函數的入口</p> <p>2.setup函數接收兩個參數:props、context(包含attrs、slots、emit)</p> <p>3.setup函數是處於生命周期函數 beforeCreate之前執行,執行setup函數時組件實例並未被創建,this不指向vue實例</p> <p>4.與模板一起使用:須在ref或reactive中聲明然后return出去使用才是響應式的</p> <p>5.使用渲染函數:可以返回一個渲染函數,該函數可以直接使用在同一作用域中聲明的響應式狀態</p> <h2>二、setup第一個參數props</h2> <p>props 是響應式的,當傳入新的 prop 時,它將被更新。</p> <div class="js_warp"> <p>export default {</p> <p>props: {</p> <p>title: String</p> <p> },</p> <p>setup(props) {</p> <p>console.log(props.title)</p> <p>}</p> <p>}</p> </div> <h2>因為 props 是響應式的,不能使用 ES6 解構,會消除 prop 的響應性。</h2> <p>如果需要解構 prop,可以在 setup 函數中使用 [toRefs]函數來完成此操作:</p> <div class="js_warp"> <p>setup(props) {</p> <p> const { title } = toRefs(props)</p> <p> return{ title }</p> <p> },</p> </div> <h2>三、setup第二個參數context</h2> <p>context 是一個普通 JavaScript 對象,暴露了其它可能在 setup 中有用的值</p> <div class="js_warp"> <p>setup(props, context) {</p> <p>// Attribute (非響應式對象,等同於 $attrs)</p> <p>console.log(context.attrs)</p> <p> // 插槽 (非響應式對象,等同於 $slots)</p> <p>console.log(context.slots)</p> <p>// 觸發事件 (方法,等同於 $emit)</p> <p>console.log(context.emit)</p> <p>// 暴露公共 property (函數)</p> <p>console.log(context.expose)</p> <p>}</p> </div> <h2>context不是響應的,可以用ES6進行解構</h2> <div ref="footer"></div> </div> </div> </div> </template>
可以有兩種方式導出
引入基礎模塊
import html2canvas from 'html2canvas'
import jsPDF from 'jspdf'
data() { return { htmlTitle: '頁面導出PDF文件名', //這個也是固定寫法,pdf文件下載的名稱 },
1:第一種不分頁面
methods:{
// 下載pdf文件 不分頁
downLoadPdf(){
window.scrollTo(0, 0);
const element = document.querySelector('#pdfDom') ;// 這個dom元素是要導出pdf的div容器
setTimeout(() => {
html2canvas(element, {
height: this.$refs.footer.offsetTop,
useCORS: true // 如果說所生成的頁面中帶有跨域的圖片,這個useCors需要設置為True 否則畫布被污染不會顯示
}).then((canvas) => {
console.log(canvas);
const contentWidth = canvas.width;
const contentHeight = canvas.height;
// 一頁pdf顯示html頁面生成的canvas高度;
const pdfX = (contentWidth + 100) / 2 //* 0.975;
const pdfY = (contentHeight + 100) / 2 //* 0.975;// 500為底部留白
const imgX = pdfX;
const imgY = (contentHeight / 2);// 內 * 0.75
const pageData = canvas.toDataURL('image/png', 1.0);
const pdf = new jsPDF('', 'pt', [pdfX, pdfY]);
// 有兩個高度需要區分,一個是html頁面的實際高度,和生成pdf的頁面高度(841.89)
// 內容未超過pdf一頁顯示的范圍,無需分頁
pdf.addImage(pageData, 'png', 0, 0, imgX, imgY);
pdf.save(12 + '.pdf'); // 生成的文件名字
})
},10)
},
}
導出效果:
2:第二種 導出pdf分頁
methods:{ // 下載pdf文件 分頁 getPdf(){ var title = this.htmlTitle html2canvas(document.querySelector('#pdfDom'), { allowTaint: true, useCORS: true }).then(function (canvas) { let contentWidth = canvas.width let contentHeight = canvas.height let pageHeight = contentWidth / 592.28 * 841.89 let leftHeight = contentHeight let position = 0 let imgWidth = 595.28 let imgHeight = 580.28 / contentWidth * contentHeight let pageData = canvas.toDataURL('image/jpeg', 1.0) let PDF = new jsPDF('', 'pt', 'a4') if (leftHeight < pageHeight) { PDF.addImage(pageData, 'JPEG', 0, 0, imgWidth, imgHeight) } else { while (leftHeight > 0) { PDF.addImage(pageData, 'JPEG', 0, position, imgWidth, imgHeight) leftHeight -= pageHeight position -= 841.89 if (leftHeight > 0) { PDF.addPage() } } } PDF.save(title + '.pdf') } ) }, }
導出效果: