vue实现HTML转PDF (已解决清晰、页边距、图片跨域导出等问题)

最近有需求做简历打印的功能,就又花时间研究了一下html转图片导出,里面牵扯到多页pdf导出时的分页和页边距问题,清晰度问题以及图片跨域问题等。我们一个一个来解决。

一、先说HTML转PDF的实现方法

1. 我们要先添加两个模块

第一个.将页面html转换成图片
npm install --save html2canvas 
第二个.将图片生成pdf
npm install jspdf --save

2. 在utils文件夹下面创建一个htmlToPdf.js文件,写入如下代码:

// 页面导出为pdf格式
import html2Canvas from 'html2canvas'
import jsPDF from 'jspdf'

const htmlToPdf = {
    getPdf(title,url) {
        html2Canvas(document.querySelector('#pdfDom'), {
            allowTaint: false,
            taintTest: false,
            logging: false,
            useCORS: true,
            dpi: window.devicePixelRatio*4, //将分辨率提高到特定的DPI 提高四倍
            scale:4 //按比例增加分辨率
        }).then(canvas=>{
            var pdf = new jsPDF('p', 'mm', 'a4');    //A4纸,纵向
            var ctx = canvas.getContext('2d'),
                a4w = 190, a4h = 277,    //A4大小,210mm x 297mm,四边各保留10mm的边距,显示区域190x277
                imgHeight = Math.floor(a4h * canvas.width / a4w),    //按A4显示比例换算一页图像的像素高度
                renderedHeight = 0;

            while(renderedHeight < canvas.height) {
                var 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();//如果后面还有内容,添加一个空页
                }
                // delete page;
            }
            //保存文件
            pdf.save(title + '.pdf')
        })
    }
};

export default htmlToPdf;

3. 在我们需要的页面使用我们定义的函数文件。

import html2canvas from "html2canvas";

4. 在执行下载的方法中调用html2canvas中的getPdf方法即可。

html

// ... 需要打印的内容

js

onClickDownLoad() {
	htmlToPdf.getPdf('下载名称');
},

至此,我们的HTML转PDF的功能也就实现了。

但是在实现的过程中,我们会发现以下问题:

1. 因为实现的方法是先利用canvas转成图片,然后转pdf,所以会存在导出模糊的情况。

2. 导出的pdf页边距的问题。

3. 当要打印的区域存在跨域图片时,方法会报错。

问题已经找出来,接下来当然就是一个一个解决问题喽,哈哈。

问题1. 转pdf,所以会存在导出模糊的情况

解决的原理就是通过放大canvas转图片时的大小

dpi: window.devicePixelRatio*4, //将分辨率提高到特定的DPI 提高四倍
scale:4 //按比例增加分辨率

问题2. 导出的pdf页边距的问题

在图片转pdf的时候,提前把pdf的页边距留出来,再去计算图片的放置尺寸。

var pdf = new jsPDF('p', 'mm', 'a4');    //A4纸,纵向
var ctx = canvas.getContext('2d'),
    a4w = 190, a4h = 277,    //A4大小,210mm x 297mm,四边各保留10mm的边距,显示区域190x277
    imgHeight = Math.floor(a4h * canvas.width / a4w),    //按A4显示比例换算一页图像的像素高度
    renderedHeight = 0;

    while(renderedHeight < canvas.height) {
        var 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();//如果后面还有内容,添加一个空页
        }
        // delete page;
     }

问题3. 图片跨域

在解决图片跨域的过程中,我试过了网上的方法,说是还需要在跨域的服务器上配置一些参数,比较麻烦,还是前端自己解决吧。

然后尝试把图片转base64(可以搜索图片转base64的方法),之后,图片跨域问题完美解决,很是开心。还是要记得先为跨域的图片做下代理(图片地址:http://118.190.75.53/portal_pic/item/3de47b6bf40747d495728cf6441e4a62.jpg)

proxy: {
    '/portal_pic': {
		target: "http://118.190.75.53/"
    },
},
this.getBase64Image(this.baseInfo.basic.interviewHead);

// 第一个参数是图片的URL地址,第二个是转换成base64地址后要赋值给的img标签
getBase64Image(url = "") {
    if (!url) return;
	let link = url;
	link = link.split("118.190.75.53");
	if (link.length > 1) link = link[1];
	var that = this;
	var image = new Image();
	console.log(url, "url");
	image.src = link + "?v=" + Math.random(); // 处理缓存
	image.crossOrigin = "*"; // 支持跨域图片
	image.onload = function() {
		var base64 = that.drawBase64Image(image);
		that.baseInfo.basic.interviewHead = base64;
		console.log(that.baseInfo, that.baseInfo.basic);
	};
},
drawBase64Image(img) {
	var canvas = document.createElement("canvas");
	canvas.width = img.width;
	canvas.height = img.height;
	var ctx = canvas.getContext("2d");
	ctx.drawImage(img, 0, 0, img.width, img.height);
	var dataURL = canvas.toDataURL("image/png");
	return dataURL;
},

好了,遇到的问题已经解决,功能实现,可以愉快的下载pdf文件了,哈哈!

(在此顺便记录一下实现转pdf的另一种简单的方式,window.print(),这种方法是通过调用网页上面的打印方法,缺点就是有些地方可能会打印不准确。)

你可能感兴趣的:(vue.js,vue)