前端vue实现打印 / 下载

570 阅读2分钟

html2canvas

html2canvas是在浏览器上对网页进行截图操作,实际上是操作DOM。

image.png

html2canvas

如果下载出来是pdf文件,可以加上jspdf插件,会先通过html2canvas把页面转化成base64图片,再通过jspdf导出。

image.png

安装

npm i html2canvas jspdf
或
yarn add html2canvas jspdf

常用配置项

参数类型默认值描述
allowTaintbooleanfalse是否允许跨域图像污染画布
useCORSbooleanfalse是否跨域加载图片
backgroundColorstring#fff背景色
widthnumber元素宽度单元格
heightnumber元素高度单元格
scalenumberwindow.devicePixelRatio缩放比例
scrollXnumber元素x轴滚动位置生成后x轴滚动位置
scrollYnumber元素y轴滚动位置生成后y轴滚动位置

使用

如果需要下载pdf再打开,可以直接pdf.save(name + time),后面的就可以注释了。 不需要的话把pdf.save(name + time)注释,页面打印完成后直接打开新标签展示pdf。

<template>
  <div>
    <h1 ref="toPdf">
      导出区域
    </h1>
    <button @click="toPdfFn">导出pdf</button>
  </div>
</template>

<script>
import html2canvas from "html2canvas";
import JSPDF from "jspdf";
export default {
 methods:{
  toPdfFn(){
   this.htmlToPdf('文件名','时间')
  },
  htmlToPdf(name,time){
      let element = this.$refs.toPdf
      html2canvas(element, {
       	logging: false,
	allowTaint: true,  //开启跨域
	useCORS: true,
	width: 595,
	scale: 2, // 处理模糊问题
	dpi: 300, // 处理模糊问题
        height:element.availHeight, //解决下方白边问题
      }).then(function(canvas) {
        let pdf = new JSPDF("p", "mm", "a4") // A4纸,纵向
        let ctx = canvas.getContext("2d")
        let a4w = 190;
        let a4h = 277 // A4大小,210mm x 297mm,四边各保留20mm的边距,显示区域190x277
        let imgHeight = Math.floor(a4h * canvas.width / a4w) // 按A4显示比例换算一页图像的像素高度
        let renderedHeight = 0
        while (renderedHeight < canvas.height) {
          let page = document.createElement("canvas")
          page.width = canvas.width
          page.height = Math.min(imgHeight, canvas.height - renderedHeight) // 可能内容不足一页

          // 用getImageData剪裁指定区域,并画到前面创建的canvas对象中
          page.getContext("2d").putImageData(ctx.getImageData(0, renderedHeight, canvas.width, Math.min(imgHeight,
            canvas.height - renderedHeight)), 0, 0)
            
          pdf.addImage(page.toDataURL("image/jpeg", 1.0), "JPEG", 10, 10, a4w, Math.min(a4h, a4w * page.height /
            page.width)) // 添加图像到页面,保留10mm边距

          // 如果后面还有内容,添加一个空页
          renderedHeight += imgHeight
          if (renderedHeight <= canvas.height) {
            pdf.addPage()
          }
        }
     
        //下载pdf 打开
	// pdf.save(name + time)
	// 将 PDF 文档转换为 Blob 对象
	const blob = pdf.output('blob');
	// 创建 URL 对象并指向该 Blob 对象
	const url = URL.createObjectURL(blob);
	// 使用 iframe 加载 PDF 文件并直接显示
	const iframe = document.createElement('iframe');
	iframe.style.display = 'none';
	iframe.src = url;
	document.body.appendChild(iframe);
	// 使用 window.open() 方法在新窗口中打开 PDF 文件
	window.open(url, '_blank');
      })
    }
 }
}
</script>

记录下使用时遇到的问题

使用html2canvas截图的时候,需要截图的dom内css不要用transform实现居中,会丢失。
使用html2canvas将div倾斜时,transform: skew(-15deg, 0deg);打印部分显示不出来。
使用font-family: Songti SC-Black, Songti SC; 失效。 更换字体: font-family: 'STZhongsong';
打印出来模糊问题,使用: scale: 2, //处理模糊问题 dpi: 300, // 处理模糊问题 ( 看上方代码 );
html2Canvas打印时,使用网络图片跨域问题, 首先在线图片域名需要配置允许跨域访问。 allowTaint: true. // 开启跨域 然后img标签需要添加crossorigin="anonymous"。
<img crossOrigin="anonymous :src="url" alt="img">

解决html2canvas A4分页截断问题。

1680512707939.png

计算完后打印出来的页面

image.png

页面设计的时候就考虑到分页的情况,通过 CSS 设置高度来避免页面被分割。当然这样工作量就很大了。因为鄙人公司ui比较TM的**(可爱) 1px 都要跟你算好久(你们公司的ui是这样吗?), 所以就选择通过css来计算绘制。思路: A4纸的宽高都是固定的,A4纸像素长宽分别是842×595。 一个页面来进行展示,子组件单独写样式。
<template>
  <div>
    <button @click="toPdfFn">导出pdf</button>
    <html2Pdf ref="toPdf">
      导出区域
    </html2Pdf>
  </div>
</template>
一页高度就是固定的,然后根据设计稿来就行了! 懂的都懂 (手动狗头)
<section class="PDF"> 内容 </section>

.PDF {
	text-align: center;
	width: 595px;
	height: 842px;
        background: #FFFFFF;
	border-radius: 0px 0px 0px 0px;
        opacity: 1;
    }

有问题可以留言一起讨论~