html2canvas+jspdf 分页截断

前言

 废话有时间再写,这个功能是在其他人分享的源代码的基础上修改的,只为了完成功能。

方法调用 

var $el = document.getElementById("table");
exportToPDF($el);

jspdf打印

function exportToPDF(element) {
    var pdf = jspdf.jsPDF('', 'pt', 'a4');
    // A4纸张的宽度和高度
    var A4_WIDTH = 592.28;
    var A4_HEIGHT = 841.89;
    // A4实际内容宽度
    var CONTENT_WIDTH = 560;
    // 距离PDF左边的距离,/ 2 表示居中
    var baseX = (A4_WIDTH - CONTENT_WIDTH) / 2; // 预留空间给左边
    var baseY = 15;
    // 除去间距后,页面内容的实际高度
    var CONTENT_HEIGHT = A4_HEIGHT - 2 * baseY;
    // PDF内容宽度和在HTML中宽度的比值
    var rate = CONTENT_WIDTH / element.getBoundingClientRect().width;
    // 每一页的分页坐标, PDF高度, 初始值为根元素距离顶部的距离
    var pages = [rate * getElementTop(element)];
    //计算页面的高度
    var pageHeight = Math.ceil(rate * A4_HEIGHT);
    // 一页的高度, 转换宽度为一页元素的宽度
    toCanvas(element, CONTENT_WIDTH).then(function (canvas) {
        var width = canvas.width;
        var height = canvas.height;
        var data = canvas.data;
        // 深度遍历节点的方法
        traversingNodes(document.querySelectorAll("tr"));
        // 对pages进行一个值的修正,因为pages生成是根据根元素来的,根元素并不是我们实际要打印的元素,而是element,
        // 所以要把它修正,让其值是以真实的打印元素顶部节点为准
        var newPages = pages.map((item) => item - pages[0]);
        // 根据分页位置 开始分页
        for (var i = 0; i < newPages.length; ++i) {
            // 根据分页位置新增图片
            addImage(
                baseX,
                baseY - newPages[i],
                pdf,
                data,
                width,
                height
            );
            // 对于除最后一页外,对 内容 的多余部分进行遮白处理
            if (i < newPages.length - 1) {
                // 获取当前页面需要的内容部分高度
                var imageHeight = newPages[i + 1] - newPages[i];
                console.log(12121, baseY + imageHeight, baseY * 2 + imageHeight);
                // 对多余的内容部分进行遮白
                addBlank(
                    0,
                    baseY + imageHeight,
                    A4_WIDTH,
                    A4_HEIGHT - imageHeight
                );
            }
            // 若不是最后一页,则分页
            if (i !== newPages.length - 1) {
                // 增加分页
                pdf.addPage();
            }
        }
        pdf.save('a.pdf');
    });
    // 添加
    function addImage(_x, _y, pdfInstance, base_data, _width, _height) {
        pdfInstance.addImage(base_data, 'JPEG', _x, _y, _width, _height);
    }

    // 增加空白遮挡
    function addBlank(x, y, _width, _height) {
        pdf.setFillColor(255, 255, 255);
        pdf.rect(x, y, Math.ceil(_width), Math.ceil(_height), 'F');
    }
    // 获取该元素到页面顶部的高度(注意滑动scroll会影响高度)
    function getElementTop(contentElement) {
        if (contentElement.getBoundingClientRect) {
            var rect = contentElement.getBoundingClientRect() || {};
            // 考虑滚动条对高度的影响
            var topDistance = rect.top + window.scrollY;
            return topDistance;
        }
    }
    // 遍历元素节点
    function traversingNodes(nodes, height) {
        for (var element of nodes) {
            var one = element;
            // table的每一行元素也是深度终点
            var isTableRow = one.nodeName == 'tr';
            // 对需要处理分页的元素,计算是否跨界,若跨界,则直接将顶部位置作为分页位置,进行分页,且子元素不需要再进行判断
            var { offsetHeight } = one;
            // 计算出最终高度
            var offsetTop = getElementTop(one);
            // dom转换后距离顶部的高度
            // 转换成canvas高度
            var top = rate * offsetTop;
            var rateOffsetHeight = rate * offsetHeight;
            // 对于深度终点元素进行处理
            if (isTableRow) {
                // dom高度转换成生成pdf的实际高度
                // 代码不考虑dom定位、边距、边框等因素,需在dom里自行考虑,如将box-sizing设置为border-box
                updateTablePos(rateOffsetHeight, top);
            }
            // 对于普通元素,则判断是否高度超过分页值,并且深入
            else {
                // 执行位置更新操作
                updateNormalElPos(top);
                // 遍历子节点
                traversingNodes(one.childNodes);
            }
            updatePos(height);
        }
    }
    // 普通元素更新位置的方法
    // 普通元素只需要考虑到是否到达了分页点,即当前距离顶部高度 - 上一个分页点的高度 大于 正常一页的高度,则需要载入分页点
    function updateNormalElPos(top) {
        if (
            top - (pages.length > 0 ? pages[pages.length - 1] : 0) >=
            CONTENT_HEIGHT
        ) {
            pages.push(
                (pages.length > 0 ? pages[pages.length - 1] : 0) + CONTENT_HEIGHT
            );
        }
    }
    function updateTablePos(eHeight, top) {
        // 如果高度已经超过当前页,则证明可以分页了
        if (top - (pages.length > 0 ? pages[pages.length - 1] : 0) >= CONTENT_HEIGHT) {
            pages.push(
                (pages.length > 0 ? pages[pages.length - 1] : 0) + CONTENT_HEIGHT
            );
        } else if (top + eHeight - (pages.length > 0 ? pages[pages.length - 1] : 0) > CONTENT_HEIGHT
            && top !== (pages.length > 0 ? pages[pages.length - 1] : 0)) {
            // 若 距离当前页顶部的高度 加上元素自身的高度 大于 一页内容的高度, 则证明元素跨页,将当前高度作为分页位置
            pages.push(top);
        }
    }
    function updatePos(height) {
        while (pages[pages.length - 1] + CONTENT_HEIGHT < height) {
            pages.push(pages[pages.length - 1] + CONTENT_HEIGHT);
        }
    }
};

html2canvas转为图片 

function toCanvas(element, width) {
    if (!element) {
        return Promise.resolve({ width: width, height: 0 });
    }

    return new Promise(function (resolve, reject) {
        html2canvas(element, {
            // allowTaint: true, // 允许渲染跨域图片
            scale: 1.4, // 增加清晰度
            dpi: 300,
            useCORS: true // 允许跨域
        }).then(function (canvas) {
            // 获取canvas转化后的宽高
            var canvasWidth = canvas.width;
            var canvasHeight = canvas.height;

            // html页面生成的canvas在pdf中的高度
            var height = (width / canvasWidth) * canvasHeight;

            // 转化成图片Data
            var canvasData = canvas.toDataURL('image/jpeg', 1.0);

            resolve({ width: width, height: height, data: canvasData });
        }).catch(function (error) {
            reject(error);
        });
    });
}

参考:

JSPDF + html2canvas A4分页截断

JSPDF + html2canvas A4分页截断源代码

效果演示 (大概就是这样)

### 回答1: HTML2Canvas是一个将HTML DOM元素转换为canvas的JavaScript库,而jspdf是一个用于生成PDF文档的JavaScript库。因此,您可以使用HTML2Canvas将HTML DOM元素转换为Canvas,然后使用jspdf将Canvas转换为PDF。 要处理分页图片和被截断的文本问题,您可以使用以下步骤: 1. 将HTML DOM元素转换为Canvas。您可以使用HTML2Canvas库来完成此操作。请确保在转换时包含所有的分页图片和文本。 2. 将所有的Canvas合并在一起,以便生成单个PDF文件。您可以使用canvas.toDataURL()方法将每个Canvas转换为图像数据URL。然后,将所有的图像数据URL合并在一起,并使用jspdf将它们转换为PDF。 3. 处理被截断的文本。如果文本被截断,您可以使用CSS的white-space属性来处理它。例如,您可以设置white-space:pre-wrap属性来打破单词并允许文本换行。 4. 处理分页图片。如果您有分页图片,您可以将它们分成多个Canvas,并将它们一起合并到PDF中。这将确保每个分页图片都在正确的位置显示。 总的来说,使用HTML2Canvasjspdf生成PDF文档是一个十分强大的工具。通过遵循上述步骤,您可以轻松地处理文本被截断分页图片的问题,并生成高质量的PDF文件。 ### 回答2: html2canvas是一个javascript库,用于将HTML元素渲染为Canvas,并提供了将Canvas导出为图片的功能。而jspdf是另一个javascript库,用于生成PDF文件。 使用html2canvasjspdf可以实现在前端生成PDF文件的功能。首先,使用html2canvas将HTML页面的内容渲染为Canvas。然后,将Canvas转换为图像数据,并将图像数据添加到jspdf的PDF文件中。最后,可以将生成的PDF文件保存或下载。 但是在处理分页时,把整个HTML页面转换为Canvas,可能会导致图片和文字被截断的问题。这是因为Canvas在渲染时有大小限制。 为了解决这个问题,可以通过在特定位置手动分页来控制页面内容的展示。首先,确定每一页需要展示的内容,并在对应的位置手动分页。具体的做法是使用CSS的page-break属性来设置页面的分页位置,以确保每一页不会出现图片和文字被截断的情况。 在使用html2canvas时,可以通过设置ignoreElements属性来忽略某些元素不进行渲染,以避免被截断。例如,对于需要分页的图片,可以在转换为Canvas时,将其设置为忽略的元素,保证图片完整显示在各个页面中。 总而言之,使用html2canvasjspdf可以在前端实现PDF文件的生成,但处理分页时需要注意图片和文字被截断的问题。通过手动设置分页位置和忽略特定元素,可以解决这个问题,确保生成的PDF文件中的内容完整可读。 ### 回答3: html2canvas是一个JavaScript库,可以将HTML元素转换为canvas画布,并且可以配合jspdf库生成PDF文件。 要处理分页图片和文字被截断的问题,可以按照以下步骤进行: 1. 引入html2canvasjspdf库。 2. 创建一个用于生成PDF的按钮或者其他触发事件。 3. 使用html2canvas库将需要转换为PDF的HTML元素转换为canvas画布。可以使用html2canvas()方法,并将需要转换的元素传递给该方法。 4. 使用toDataURL()方法将canvas画布转换为一个base64编码的图像字符串。 5. 创建一个jspdf实例。可以使用`new jsPDF()`创建一个新的jspdf实例。 6. 使用jspdf的addImage()方法将之前生成的base64编码的图像字符串添加到页面上。可以通过指定x、y坐标和图像的宽度和高度来设置图像在PDF中的位置和尺寸。 7. 使用jspdf的save()方法保存生成的PDF文件。 对于分页图片和文字被截断的问题,html2canvasjspdf并不能自动处理。可以通过以下方法来解决: 1. 对于图片,可以在将HTML元素转换为canvas之前,通过调整元素的尺寸、位置或者裁剪来确保图片完整显示在一个页面中。 2. 对于文字,可以通过调整元素的字体大小、行高或者缩减内容来确保文字完整显示在一个页面中。 3. 如果需要处理多页的情况,可以使用循环或者递归的方式将分页的内容分别转换为canvas,并通过jspdf的addPage()方法在PDF中添加新的页面。 总结来说,通过html2canvasjspdf配合使用,可以在前端生成PDF文件。对于处理分页图片和文字被截断的问题,需要手动调整HTML元素的尺寸、位置和内容,以确保完整显示在PDF中。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值