88

我正在用一张表格从 html 页面生成 pdf 报告。

我为此目的使用wkhtmltopdf

生成 pdf 时,它会在 tr tag 中的任何位置中断

我想避免它。

4

18 回答 18

164

17.09.2015更新:检查您使用的版本:wkhtmltopdf 0.12.2.4 据说可以解决问题(我没有检查)


这是 wkhtmltopdf 中的一个已知问题。webkit 使用的分页算法(WKhtmltopdf 中的 WK)对于大表并不适用。我建议将表格分解成更小的块,这些块更容易拆分为页面并大量使用 css:

table, tr, td, th, tbody, thead, tfoot {
    page-break-inside: avoid !important;
}

还请查看以下 wkhtmltopdf 问题,他们有有趣的评论,例如讨论表拆分问题。有一个 JS 解决方案可以以编程方式将表拆分为 168,这可能会对您有所帮助(虽然我不使用它)。

更新 08.11.2013 上面链接的第 168 期对此进行了很多讨论。有人设法编译了一个支持更好的分表的 wkhtmltopdf 版本,但不幸的是,它似乎没有正式发布并且可能包含其他错误。我不知道如何获取它,也不知道如何在 Windows 上编译,但任何有兴趣的人都可以查看这里的评论(请参阅下面的新更新)。

2014 年 2 月 24 日更新 您会很高兴听到在 wkhtmltopdf 0.12 中此功能已得到极大改进。然而,在开始使用任何新版本之前等待 0.12.1 并彻底测试,尽管使用 antialize 的新人做得很好(ashkulz 摇滚),但它仍然有点不稳定!在wkhtmltopdf.orggithub保持更新。谷歌代码站点已经过时并且正在缓慢迁移。

于 2012-11-23T09:01:26.887 回答
21

这是旧帖子,但由于我浪费了很多时间试图找到合适的解决方案,我会把它放在这里,也许它会对某人有用。

所以从我读到的,问题是

page-break-inside: avoid

是它不起作用。但实际上,如果您将它设置在可以按预期工作的元素上display:block(如 SO 中的某处所述)。所以对于表格css的简单结构

td div, th div{
    page-break-inside: avoid;
}

和表结构

<table>
....
<tr>
    <td><div>some text</div></td>
    <td><div>more text</div></td>
</tr>
....
</table>

将按预期工作。

我的行跨度有点复杂,所以上面的解决方案是将其打破,这不是预期的效果。我使用 div 为每行跨行集解决了这个问题。我的 jquery js 完成了所有的工作:

$(window).load(function () {
    var sizes = {};
    $('#the_table tr:first th').each(function (a, td) {         
        var w = $(td).width();
        if (sizes.hasOwnProperty('' + a)) {
            if (sizes['' + a] < w)
                sizes['' + a] = w;
        }
        else {
            sizes['' + a] = w;
        }
    });

    var tableClone = $('#the_table').clone();
    $('#the_table').replaceWith('<div class="container"></div>');

    var curentDivTable;
    var cDiv = $('.container');
    tableClone.find('tr').each(function (i, ln) {
        var line = $(ln);
        if (line.hasClass('main_row')) {
            var div = $('<div class="new-section"><table><tbody>')
            currentDivTable = div.find('tbody');
            cDiv.append(div);               
        }
        currentDivTable.append(line);
    });
    //optional - maybe in % its better than px
    var sum = 0;
    $.each(sizes, function (a, b) {
        sum += b;
    });
    var widths = {};
    $.each(sizes, function (a, b) {
        var p = Math.ceil(b * 100 / sum);
        widths['' + a] = p + '%';
    });
    //setup
    $('.container table').each(function (a, tbl) {
        $(tbl).find('tr:first td, tr:first th').each(function (b, td) {
            $(td).width(widths['' + b]);
        });
        $(tbl).addClass('fixed');
    });
});

CSS:

div.new-section {
    page-break-inside: avoid;
}
.container, .new-section, .new-section table.fixed{
    width: 100%;
}

.new-section table.fixed{
    table-layout:fixed;
}

我不知道是否需要一切,我不认为它是完美的,但它可以完成工作。仅在 chrome 上测试

于 2013-08-31T18:43:57.370 回答
19

自 0.12 以来,此问题已得到解决,但有时,当表格太长而无法放入页面时,wkhtmltopdf 会将其分成两部分并在新页面上重复列标题,并且这些列标题会叠加到第一行。

我在 wkhtmltopdf github 问题部分找到了这个问题的临时解决方案: https ://github.com/wkhtmltopdf/wkhtmltopdf/issues/2531

只需将此行添加到您的视图 css 中:

tr {
  page-break-inside: avoid; 
}
于 2015-09-15T12:25:05.657 回答
9

我已经研究了几天这个问题,终于找到了完美的解决方案。你可以参考这个项目phpwkhtmltopdf。查看目录article,您会发现 3 个问题的 3 个解决方案。总之,最终的解决方案是添加css样式

thead {
    display: table-row-group;
}
tr {
    page-break-before: always;
    page-break-after: always;
    page-break-inside: avoid;
}
table {
    word-wrap: break-word;
}
table td {
    word-break: break-all;
}

如果您是中国人,请随时查看有关 wkhtmltopdf 的网站,您一定想知道这些 如果您想了解 wkhtmltopdf的要点,请查看要点

于 2018-01-10T08:31:54.707 回答
5

在我的特殊情况下,由于某种原因,以前的答案都没有对我有用。最终起作用的实际上是几件事的结合。

  1. 我使用 pip3 安装了(在 Ubuntu 16.04 中)名为 pdfkit 的 Wkhtmltopdf python 包装器,然后我没有通过 apt-get 安装 Wkhtmltopdf,而是按照下面的脚本安装了静态二进制文件(版本 0.12.3),取自此处

    #!/bin/sh
    
    sudo apt-get install -y openssl build-essential xorg libssl-dev
    wget http://download.gna.org/wkhtmltopdf/0.12/0.12.3/wkhtmltox-0.12.3_linux-generic-amd64.tar.xz
    tar -xJf wkhtmltox-0.12.3_linux-generic-amd64.tar.xz
    cd wkhtmltox
    sudo chown root:root bin/wkhtmltopdf
    sudo cp -r * /usr/
    
  2. 添加了这个 CSS(如这里的答案之一所建议的那样):

    tr, td div, th div{
        page-break-inside: avoid;
    }
    
  3. 然后按照这里的建议添加<thead><tbody>标签(没有这些,表格仍然会以一种丑陋的方式破坏):

    <table>
        <thead>
            <tr>
                <th>Column 1</th>
                <th>Column 2</th>
            </tr>
        </thead>
    
        <tbody>
            <tr>
                <td>Value 1</td>
                <td>Value 2</td>
            </tr>
        </tbody>
    </table>
    

通过这些修改,我现在可以成功地使用Mako 模板生成 HTML,然后将其提供给 Wkhtmltopdf 并获得精美的分页 PDF。

于 2017-02-08T21:36:57.010 回答
4

我尝试了对我的表格进行各种操作,但我尝试的任何方法都无法阻止将分页符放在一行的中间。无奈之下,我尝试了不同的版本,结果如​​下:

Wkhtmltopdf 0.12.2.1:不好

Wkhtmltopdf 0.12.3:不好

Wkhtmltopdf 0.12.1:好

我的解决方案是降级到版本 0.12.1,这解决了我的问题。诚然,他们可能部分是由于我对我的 html 不是超级强迫症,但由于 HTML 是在 TinyMCE 内部生成的(由用户),我真的没有太多选择。

此外,嵌套表不适用于我的任何版本。

于 2016-08-12T06:57:30.307 回答
3

我遇到了同样的问题,经过大量的试验 n 错误后,这个 css 解决了这个问题

tr {
    display: inline-table;
}
于 2017-11-13T06:07:23.853 回答
2

如何在不中断 tr 的情况下在 pdf 中使用分页符?

这是您可以在任何 html 文件中使用的解决方案.....

启动 tr 后,您必须在 tr 中取一个 div 并将这个 css 提供给 div:

<tr>
      <div style="page-break-inside:avoid !important; page-break-after:auto !important; overflow: hidden; display:block !important; width:100% ">
     </tr>
于 2018-01-12T07:17:30.400 回答
2

我结合使用一些建议的解决方案解决了这个问题。

我将表格包装在一个 div 中并定义了以下 CSS。

.wrapping-div {
        display: block;
        page-break-inside: avoid !important;
    }

.wrapping-div table, .wrapping-div tbody, .wrapping-div tr, .wrapping-div td, .wrapping-div th {
        page-break-inside: avoid !important;
    }

完成后的表结构定义如下示例:

<div class="wrapping-div">
 <table>
  <tbody>
   <tr>
    <th>
      header
    </th>
    <td>
      content
    </td>
   </tr>
  </tbody>
 </table>
</div>

我不需要在 td 或 th 标签内创建任何 div 。

我在尝试解决问题时注意到的重要事项:

  • tbody 必须包含在表中
  • div 必须有 display: block
  • 当一个表格不适合一个页面时,它会自动将整个表格移动到下一页(我没有尝试过这个巨大的表格)
  • 如果您只从 CSS 中删除“.wrapping-div table”选择器,它将允许将表格分成两页,但会正确呈现它,而不是在两页中破坏一个单元格(这就像 Word 上的默认行为)

我希望这有帮助。

于 2018-07-19T16:32:02.507 回答
1

除了 Nanotelep 所说的,这里是手动表格分页算法的工作实现。 https://github.com/Averin/JSUtils/tree/master/wkhtmltopdfTableSplitHack

于 2013-05-30T11:13:03.017 回答
1

上面的答案对我不起作用。我必须专门禁用我的 pdfkit 配置的缩放选项。

PDFKit.configure do |config|

  config.default_options = {
    print_media_type: false,
    page_size: "A4",
    encoding: "UTF-8",
    ## Make sure the zoom option is not enabled!
    ## zoom: '1.3',
    disable_smart_shrinking: false,
    footer_right: "Page [page] of [toPage]"
  }

end
于 2013-08-18T22:09:58.997 回答
1

对于任何对此仍有疑问的人,要记住的一件事是table必须是body的直接子级,否则 css 将无法工作(至少这就是我发生的事情)。

于 2015-11-20T19:57:00.973 回答
1

我找到了这个荒谬的解决方案,但它对我来说效果很好:)

我只是像这样放了一个很长的行跨度列

<td rowspan="XXX TOTAL ROWS" style="width:0px"></td>

然后桌子就不会破裂。

于 2016-06-22T03:37:45.863 回答
1

另一种选择:将每个tr单独放置tbody,然后将 peage break css 规则应用于tbody. 表支持多个tbodys。

一些额外的标记,但对我来说工作得体。

于 2016-06-22T21:42:37.173 回答
1

我一直在努力解决这个问题,使用最新的h4cc/wkhtmltopdf-amd64 版本 0.12.4并最终通过将包的版本降级为0.12.3!

于 2018-09-04T12:24:41.707 回答
1

为了避免分页符,我们可以使用分页符避免 css 选项。

tr { page-break-inside: avoid; }

打破任何内容(图像/文本)并使其出现在下一页

.sample-image { page-break-before: always; }
于 2019-07-23T09:48:00.087 回答
0

你有台头吗?和一个表体?

<table>
<tbody>
<tr><th>Name</th><th>Value</th></tr>
<tr><td>url</td><td>stackoverflow.com</td></tr>
<tr><td>ip</td><td>123.123.123.123</td></tr>
</tbody>
</table>

这是表格的正确格式,虽然大多数浏览器不在乎,但您提到的转换器<tbody>可以,如果您缺少或<th>标签,我建议您先尝试添加这些。

于 2012-11-22T16:17:42.677 回答
0

使用相应的类添加此 CSS

#main_div {
        position: relative;
        width: 672px; /* find your width in px based on the page margins */
    }
tr td {
        page-break-before: auto;
        page-break-inside: avoid !important;
    }

但最重要的是为包含表格(或某些父 div)的容器提供以像素为单位的固定宽度。应该适用于大多数(WebKit)pdf 生成器,并允许它们正确计算高度。

我可以确认在 kubuntu 20.04 中使用 wkhtmltopdf 0.12.6(带有修补的 qt)对我有用

于 2021-05-19T15:56:36.853 回答