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') } ) }, }
导出效果: