html2canvas+jspdf踩坑之路

最近刚完成了项目中所有模块的详情页导出pdf功能。本来开始后端接了这个活,前端只要传过去单号就好,可是做到最后一直实现不来,页面总是显示一半,于是,后端把活让给了我😢
还好,同组的其他伙伴项目中有用到过,给了我些帮助。
具体实现思路是:html2canvas 截屏页面快照,然后把照片插入到pdf页面内。
遇到的问题有:
1) 快照是空白的
首先页面DOM布局很重要,如果布局比较乱,很容易打印出空白页面。我们要知道html2canvas 截屏的元素是相对body元素定位的,所以我这里把要截屏的DOM元素copy了一份,放在body元素里。

            let targetDom = document.querySelector('#pdfWrap');
            let copyDom = targetDom.cloneNode(true);
            copyDom.classList.add("copydom");
            document.body.appendChild(copyDom);

但是这样也有问题,所以要从新缕清布局,尽量不要copy元素,因为cloneNode(true)无法copy echarts画出的图表~

2)pdf宽度很大,在a4纸打印不够
         打印出来的PDF是等比例的缩放字体大小,如果宽度很宽,字体就会变得很小很小。这个时候就要和PM沟通协商,看看想怎么解决。
3)快照图片不显示
原因是跨域请求了图片资源,html2canvas 默认是不跨域的,所以在这里要设置下可跨域。

<img :src="item.path+'?'+new Date().getTime()" crossOrigin="anonymous"/>
        html2canvas(copyDom, {
            useCORS: true

4)快照截屏是当前可视窗口大小,没法滚动
         我们页面比较长,有滚动条,所以会出现当前问题。设置当前要截屏的DOM元素的宽度和高度都为目标元素的滚动高度。

            copyDom.style.height = targetDom.scrollHeight  + "px";
            copyDom.style.width = targetDom.scrollWidth  +  "px";

5)页面表格内容超出用省略号显示的解决办法
         和PM沟通,需要把省略掉掉内容折行展示出来。html2canvas 的截图原则是所见即所得,所以页面是什么样子,打印出来是什么样子。因此,我需要在新的copy DOM元素下改变折行样式。(增加这行类名:export-mulit-line)

 let recordDom = copyDom.getElementsByClassName('approval-records')[0];
let recordTableDom = recordDom.getElementsByClassName('data-table')[0];
recordTableDom.classList.add("export-mulit-line");

⚠️:这里涉及到了折行,页面高度会有所改变,所以要增加copyDOM元素的高度~(appendHeight即为变化的高度)

copyDom.style.height = targetDom.scrollHeight + appendHeight + "px";

总体实现代码:

        // 判断是否多行
        isMultiline(arr, num) {
            return arr.some(e => {
                return e.remark && e.remark.length > num;
        getPdf(dom, title) {
            this.loading = true;
            let targetDom = document.querySelector('#pdfWrap');
            let copyDom = targetDom.cloneNode(true);
            copyDom.classList.add("copydom");
            // 多行展示预算信息
            let appendHeight = 0;//折行增加的高度
           copyDom.style.height = targetDom.scrollHeight + appendHeight + "px";
            copyDom.style.width = targetDom.scrollWidth  +  "px";
            document.body.appendChild(copyDom);
            utils.exportPDF(copyDom, this.orgInfo.orgName).then(v => {
                this.loading = v;

utils.js

 // 导出PDF
    async exportPDF(copyDom, activityName) {
        await html2canvas(copyDom, {
            useCORS: true
            .then(canvas => {
                let contentWidth = canvas.width;
                let contentHeight = canvas.height;
                let pageHeight = contentWidth / 592.28 * 841.89;
                let leftHeight = contentHeight;
                let position = 0;
                let imgWidth = 555.28;
                let imgHeight = 555.28 / contentWidth * contentHeight;
                console.log(contentHeight);
                let pageData = canvas.toDataURL('image/jpeg', 1.0);
                let PDF = new JsPDF('', 'pt', 'a4');
                if (leftHeight < pageHeight) {
                    PDF.addImage(pageData, 'JPEG', 20, 0, imgWidth, imgHeight);
                } else {
                    while (leftHeight > 0) {
                        PDF.addImage(pageData, 'JPEG', 20, position, imgWidth, imgHeight);
                        leftHeight -= pageHeight;
                        position -= 841.89;
                        if (leftHeight > 0) {
                            PDF.addPage();
                PDF.save(activityName + '.pdf');