You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

html2canvas导出PDF遇横向滚动条内容截断,如何完整显示?

解决html2canvas导出PDF内容截断问题

问题描述

使用html2canvas将ID为to_print的div导出为PDF时,网页端可完整显示内容,但生成的PDF出现右侧内容截断的情况。当前使用的导出代码和HTML结构如下:

导出代码

function printPdf() {
    var w = document.getElementById("to_print").offsetWidth;
    var h = document.getElementById("to_print").offsetHeight;
    html2canvas(document.getElementById("to_print"), {
        dpi: 300,
        scale: 3,
        onrendered: function(canvas) {
            var img = canvas.toDataURL("image/jpeg", 1);
            var doc = new jsPDF('L', 'px', [w, h]);
            doc.addImage(img, 'JPEG', 0, 0, w, h);
            doc.save('rapport-arrivee-depart.pdf');
        }
    });
}

HTML结构

<div id="to_print">
    <div class="row">
        <div class="col-md-12" style="background-color: white">
            <div class="portlet box green">
                <div class="portlet-title">
                    <div class="caption">
                        <i class="fa fa-globe"></i><fmt:message key="HOTEL.REPORT_ARRIVAL_DEPARTURE.PAGE_BREADCRUMB.SPAN"/> </div>
                    <div class="tools"> </div>
                </div>
                <div class="portlet-body">
                    <table class="table table-striped table-bordered table-hover" id="sample_1">
                        <thead>
                            <tr>
                                <th colspan="3"></th>
                                <th class="uppercase text-center" colspan="3"><fmt:message key="COMMON.DEPARTURE.TITLE"/></th>
                                <th class="uppercase text-center" colspan="3"><fmt:message key="COMMON.ARRIVED.TITLE"/></th>
                                <th colspan="2"></th>
                            </tr>
                            <tr role="row">
                                <th class="uppercase text-center"> <fmt:message key="COMMON.NUM.CHAMBER_MIN"/> </th>
                                <th class="uppercase text-center"> <fmt:message key="COMMON.TYPE.TITLE"/> </th>
                                <th class="uppercase text-center"> <fmt:message key="COMMON.REPORT.TITLE"/> </th>
                                <th class="uppercase text-center"> <fmt:message key="COMMON.TABLE.NAME_MIN"/> </th>
                                <th class="uppercase text-center"> <fmt:message key="COMMON.ADULT_CHILD.TITLE"/> </th>
                                <th class="uppercase text-center"> <fmt:message key="COMMON.CHILD.TITLE"/> </th>
                                <th class="uppercase text-center"> <fmt:message key="COMMON.TABLE.NAME_MIN"/> </th>
                                <th class="uppercase text-center"> <fmt:message key="COMMON.ADULT_CHILD.TITLE"/> </th>
                                <th class="uppercase text-center"> <fmt:message key="COMMON.CHILD.TITLE"/> </th>
                                <th class="uppercase text-center"> <fmt:message key="COMMON.HOUR.TITLE"/> </th>
                                <th class="uppercase text-center"> <fmt:message key="COMMON.NUMBER.NIGHT"/> </th>
                            </tr>
                        </thead>
                        <tbody>
                        </tbody>
                        <tfoot>
                            <tr>
                                <th class="uppercase text-center"></th>
                                <th class="uppercase text-center"></th>
                                <th class="uppercase text-center"></th>
                                <th class="uppercase text-center"></th>
                                <th style="text-align:center"></th>
                                <th class="uppercase text-center"></th>
                                <th class="uppercase text-center"></th>
                                <th style="text-align:center"></th>
                                <th class="uppercase text-center"></th>
                                <th class="uppercase text-center"></th>
                                <th class="uppercase text-center"></th>
                            </tr>
                        </tfoot>
                    </table>
                </div>                        
            </div>
        </div>                        
    </div>
    <div class="row invoice-subtotal right" style="background-color: white">
        <div class="col-xs-3 col-xs-offset-3">
            <strong><fmt:message key="HOTEL.REPORT_ARRIVAL_DEPARTURE.NUMBER_BEDROOM_DEPARTURE"/> : <span id="bindNbDepart"><fmt:message key="COMMON.NOT.DEFINED"/></span></strong>
        </div>
        <div class="col-xs-3">
            <strong><fmt:message key="HOTEL.REPORT_ARRIVAL_DEPARTURE.NUMBER_BEDROOM_ARRIVAL"/> : <span id="bindNbArrivee"><fmt:message key="COMMON.NOT.DEFINED"/></span></strong>
        </div>
    </div>
</div>

解决方案

1. 修正元素尺寸获取逻辑

offsetWidth仅返回元素的可见宽度,当内容存在横向溢出(比如表格过宽)时,无法获取完整的内容宽度。改用scrollWidth获取元素的完整滚动宽度,同时用getBoundingClientRect()获取更精准的尺寸:

const element = document.getElementById("to_print");
const rect = element.getBoundingClientRect();
const fullWidth = element.scrollWidth; // 完整内容宽度
const fullHeight = rect.height; // 元素实际高度

2. 调整html2canvas配置

确保html2canvas捕获完整的元素内容,添加scrollX: 0、scrollY: 0避免滚动偏移,同时替换已废弃的onrendered为Promise语法(适配新版html2canvas):

html2canvas(element, {
    dpi: 300,
    scale: 3,
    scrollX: 0,
    scrollY: 0,
    useCORS: true // 若有跨域图片需开启
}).then(canvas => {
    // 后续PDF生成逻辑
});

3. 优化jsPDF的尺寸与缩放

避免直接使用px单位,改用更适合PDF的pt,同时计算内容与PDF页面的适配比例,确保完整显示:

// 获取canvas的实际尺寸
const canvasWidth = canvas.width;
const canvasHeight = canvas.height;

// 设置PDF为横向A4纸
const pdf = new jsPDF('l', 'pt', 'a4');
const pdfPageWidth = pdf.internal.pageSize.getWidth();
const pdfPageHeight = pdf.internal.pageSize.getHeight();

// 计算缩放比例,取宽高中较小的比例确保内容适配
const scaleFactor = Math.min(pdfPageWidth / canvasWidth, pdfPageHeight / canvasHeight);
const scaledWidth = canvasWidth * scaleFactor;
const scaledHeight = canvasHeight * scaleFactor;

// 居中放置内容
const xPos = (pdfPageWidth - scaledWidth) / 2;
const yPos = (pdfPageHeight - scaledHeight) / 2;

// 添加图片到PDF
pdf.addImage(canvas.toDataURL("image/jpeg", 1), 'JPEG', xPos, yPos, scaledWidth, scaledHeight);
pdf.save('rapport-arrivee-depart.pdf');

完整优化后的代码

function printPdf() {
    const element = document.getElementById("to_print");
    const rect = element.getBoundingClientRect();
    const fullWidth = element.scrollWidth;
    const fullHeight = rect.height;

    html2canvas(element, {
        dpi: 300,
        scale: 3,
        scrollX: 0,
        scrollY: 0,
        useCORS: true
    }).then(canvas => {
        const canvasWidth = canvas.width;
        const canvasHeight = canvas.height;

        // 使用A4横向纸张
        const pdf = new jsPDF('l', 'pt', 'a4');
        const pdfPageWidth = pdf.internal.pageSize.getWidth();
        const pdfPageHeight = pdf.internal.pageSize.getHeight();

        // 计算适配比例
        const scaleFactor = Math.min(pdfPageWidth / canvasWidth, pdfPageHeight / canvasHeight);
        const scaledWidth = canvasWidth * scaleFactor;
        const scaledHeight = canvasHeight * scaleFactor;

        // 居中放置内容
        const xPos = (pdfPageWidth - scaledWidth) / 2;
        const yPos = (pdfPageHeight - scaledHeight) / 2;

        pdf.addImage(canvas.toDataURL("image/jpeg", 1), 'JPEG', xPos, yPos, scaledWidth, scaledHeight);
        pdf.save('rapport-arrivee-depart.pdf');
    }).catch(err => {
        console.error('导出PDF失败:', err);
    });
}

额外建议

  • 如果表格内容极长,可考虑分页处理:通过计算内容高度与PDF页面高度的比例,拆分canvas为多个页面添加到PDF中。
  • 确保html2canvas和jsPDF使用最新版本,避免旧版本的兼容性问题。

内容的提问来源于stack exchange,提问作者pheromix

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.04 05:41:20