Cách tránh ngắt trang bên trong hàng bảng cho wkhtmltopdf


79

Tôi đang tạo báo cáo pdf từ trang html với một bảng .

Tôi đang sử dụng wkhtmltopdf cho mục đích này.

khi pdf được tạo, nó bị hỏng ở bất kỳ đâu trong thẻ tr .

Tôi muốn tránh nó.

Câu trả lời:


149

Cập nhật 17.09.2015: Kiểm tra phiên bản bạn đang sử dụng: wkhtmltopdf 0.12.2.4 được cho là khắc phục sự cố (Tôi chưa kiểm tra) .


Đây là một vấn đề đã biết trong wkhtmltopdf. Thuật toán ngắt trang được sử dụng bởi webkit (WK trong WKhtmltopdf) không thực sự hoạt động tốt cho các bảng lớn. Tôi khuyên bạn nên chia bảng thành các phần nhỏ hơn để dễ dàng chia thành các trang hơn và sử dụng css nhiều:

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

Ngoài ra, hãy xem các vấn đề wkhtmltopdf sau đây, họ có những nhận xét thú vị thảo luận về vấn đề tách bảng chẳng hạn. Có một giải pháp JS tách các bảng theo chương trình trong 168 có thể giúp bạn (tôi không sử dụng nó).

Cập nhật 08.11.2013 Có nhiều cuộc thảo luận về vấn đề này trong vấn đề 168 được liên kết ở trên. Ai đó đã quản lý để biên dịch phiên bản wkhtmltopdf hỗ trợ ngắt bảng tốt hơn, nhưng rất tiếc, có vẻ như nó không được phát hành chính thức và có thể chứa các lỗi khác. Mình không biết cách lấy và cũng không biết biên dịch trên Windows, nhưng ai quan tâm có thể kiểm tra ví dụ bình luận tại đây (xem bản cập nhật mới bên dưới).

Cập nhật 24.02.2014 Bạn sẽ rất vui khi biết rằng trong wkhtmltopdf 0.12, tính năng này trong số những tính năng khác đã được cải thiện rất nhiều. Tuy nhiên, hãy đợi 0.12.1 và kiểm tra kỹ lưỡng trước khi bắt đầu sử dụng bất kỳ phiên bản mới nào, nó vẫn còn một chút không ổn định mặc dù những người mới làm việc với antialize đang làm rất tốt (đá ashkulz)! Cập nhật liên tục tại wkhtmltopdf.orggithub . Trang web mã google đã lỗi thời và đang dần di chuyển.


1
Cảm ơn vì thông tin. Phiên bản 0.12.1 giải quyết vấn đề ngắt trang.
Nidhi Sarvaiya

1
Lưu ý, giải pháp này chỉ hoạt động với phiên bản 0.12.1 gần đây. Bất cứ điều gì trước đó vẫn không hoạt động.
Cerin

4
Tôi đã đấu tranh với điều này trong một vài ngày. Hóa ra bảng của tôi nằm trong một div với phong cách display: inline-block. Đã thay đổi nó thành blockvà những thay đổi ở trên đều bắt đầu hoạt động!
Hugh

2
@Nenotlep cảm ơn câu trả lời của bạn. vâng, tôi đã đăng một câu hỏi mới về điều này: stackoverflow.com/q/36334330/3391783 - thật buồn cười khi tất cả điều này dường như hoạt động trở lại trong các phiên bản 0.12.1-ish hoặc 0.12.2-ish và lại bị hỏng ở phiên bản 0.12. Phiên bản 3-ish.
low_rents

2
@DjDacSaunders WKHTMLTOPDF là một công cụ hack, không phải là một công cụ html -> pdf thuần túy. Mục đích của nó là hiển thị một tài liệu rất dài sang định dạng phân trang. Thực tế là chúng tôi có bất kỳ quyền kiểm soát nào đối với điều này là rất tốt. Nếu bạn muốn cải thiện điều này, nơi tốt nhất tuyệt đối để liên hệ là thượng nguồn của wkhtml, đó là dự án QT hoặc có thể là dự án WebKit. Tôi thấy trước điều này sẽ không bao giờ thay đổi vì nó không thực sự là những gì WebKit được dùng để làm khi hiển thị các trang web dưới dạng tệp PDF: / Để có toàn quyền kiểm soát, có lẽ hãy thử PrinceXML. (x) HTML không phải là một định dạng in và "giải pháp" cho vấn đề đó luôn là những bản hack.
Joel Peltonen

18

Đó là bài viết cũ, nhưng vì tôi đã mất rất nhiều thời gian để tìm giải pháp thích hợp, tôi sẽ đưa nó ở đây, có thể nó sẽ hữu ích cho ai đó.

Vì vậy, từ những gì tôi đọc, vấn đề với

page-break-inside: avoid

là nó không hoạt động. Nhưng thực sự nếu bạn đặt nó trên phần tử có display:blocknó hoạt động như mong đợi (như đã lưu ý ở đâu đó trong SO). vì vậy đối với cấu trúc đơn giản của bảng css với

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

và cấu trúc bảng

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

sẽ hoạt động như mong đợi.

Tôi gặp trường hợp phức tạp hơn một chút với ghế chèo thuyền, vì vậy giải pháp từ phía trên là phá vỡ nó thành đỉnh, điều này không mang lại hiệu quả mong muốn. Tôi đã giải quyết nó bằng cách sử dụng div cho mỗi bộ dòng được phân tách hàng. Js jquery của tôi đang làm tất cả công việc:

$(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;
}

Tôi không biết liệu mọi thứ có cần thiết hay không và tôi không nghĩ nó hoàn hảo, nhưng nó làm được việc. Chỉ thử nghiệm trên chrome


16

Kể từ 0,12, vấn đề này đã được giải quyết nhưng đôi khi, khi một bảng quá dài để vừa với trang, wkhtmltopdf sẽ chia nó thành hai phần và lặp lại các tiêu đề cột trên trang mới và các tiêu đề cột này xuất hiện chồng lên hàng đầu tiên.

Tôi đã tìm thấy giải pháp tạm thời cho vấn đề này trên phần wkhtmltopdf github sự cố: https://github.com/wkhtmltopdf/wkhtmltopdf/issues/2531

Chỉ cần thêm dòng này vào css xem của bạn:

tr {
  page-break-inside: avoid; 
}

Điều này thực sự hữu ích. Cảm ơn bạn!! Không chắc tại sao đây không phải là hành vi mặc định.
JosephK

6

Tôi đã nghiên cứu vấn đề này trong nhiều ngày và cuối cùng đã tìm ra giải pháp hoàn hảo. Bạn có thể tham khảo dự án phpwkhtmltopdf này . Nhìn vào danh bạ articlevà bạn sẽ tìm thấy 3 giải pháp cho 3 vấn đề. Tóm lại, giải pháp cuối cùng là thêm kiểu 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;
}

Nếu bạn là người Trung Quốc, vui lòng xem trang web này关于 wkhtmltopdf , 你 一定 想 知道 这些 Hãy xem ý chính nếu bạn muốn ý chính cho wkhtmltopdf


Điều này đã làm việc cho tôi. Tôi đang sử dụng wkhtmltopdf 0.12.4 . Cảm ơn!
Hugo

Tuyệt vời, đây là những gì đã làm cho tôi. Cảm ơn bạn!!!
fafafooey

5

Tôi thấy rằng wkhtmltopdf 0.12.2.1 trở đi đã khắc phục sự cố này.


7
Đo không phải sự thật. Chúng tôi vẫn còn vấn đề.
Niklas R.

1
Và đây chỉ nên là một bình luận.
Wesley Brian Lachenal

5

Trong trường hợp cụ thể của tôi vì một số lý do không có câu trả lời nào trước đây phù hợp với tôi. Những gì kết thúc hoạt động thực sự là sự kết hợp của nhiều thứ.

  1. Tôi đã cài đặt (trong Ubuntu 16.04) trình bao bọc python Wkhtmltopdf được gọi là pdfkit bằng cách sử dụng pip3 và sau đó thay vì cài đặt Wkhtmltopdf qua apt-get, tôi đã cài đặt tệp nhị phân tĩnh (phiên bản 0.12.3) bằng cách làm theo tập lệnh bên dưới, lấy từ đây

    #!/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. Đã thêm CSS này (như được đề xuất trong một trong các câu trả lời ở đây):

    tr, td div, th div{
        page-break-inside: avoid;
    }
    
  3. Và sau đó cũng thêm <thead><tbody>các thẻ như được đề xuất ở đây (nếu không có những thứ này, bảng sẽ vẫn bị hỏng một cách xấu xí):

    <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>
    

Với những sửa đổi này, giờ đây, tôi có thể sử dụng thành công các mẫu Mako để tạo HTML và sau đó cấp dữ liệu đó vào Wkhtmltopdf và có được một tệp PDF được phân trang đẹp mắt.


4

Tôi đã thử tất cả các cách thao tác với bảng của mình, nhưng không có gì tôi cố gắng có thể ngăn việc ngắt trang được đưa vào giữa một hàng. Trong tuyệt vọng, tôi đã thử các phiên bản khác nhau và tìm thấy những điều sau:

Wkhtmltopdf 0.12.2.1: Xấu

Wkhtmltopdf 0.12.3: Xấu

Wkhtmltopdf 0.12.1: Tốt

Giải pháp của tôi là hạ cấp xuống phiên bản 0.12.1, giải pháp này đã giải quyết được vấn đề của tôi. Đúng là, họ có thể một phần là do không quá OCD về html của tôi, nhưng vì HTML được tạo bên trong TinyMCE (bởi người dùng), tôi thực sự không có nhiều lựa chọn.

Ngoài ra, các bảng lồng nhau không hoạt động trong bất kỳ phiên bản nào đối với tôi.


đối với tôi 0.12.1 không giải quyết được vấn đề, và phải mất toc xa
UnixAgain

2

Tôi đã đối mặt với cùng một vấn đề, thêm vào sau rất nhiều lần thử nghiệm n lỗi css này đã giải quyết được vấn đề

tr { display: inline-table; }


2

Làm thế nào để sử dụng ngắt trang bên trong pdf mà không ngắt tr?

Đây là giải pháp mà bạn có thể sử dụng trong bất kỳ tệp html nào .....

Sau khi bắt đầu tr, bạn phải lấy một div bên trong tr và đưa css này cho div:

<tr>
      <div style="page-break-inside:avoid !important; page-break-after:auto !important; overflow: hidden; display:block !important; width:100% ">
     </tr>


1

Các câu trả lời trên không làm việc với tôi. Tôi đã phải tắt cụ thể tùy chọn thu phóng mà cấu hình pdfkit của mình.

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

1

Đối với bất kỳ ai vẫn gặp vấn đề với điều này, một điều cần nhớ là bảng phải là con trực tiếp của body , nếu không css sẽ không hoạt động (ít nhất đó là những gì đã xảy ra với tôi).


đây không phải là trường hợp của tôi - tôi có thể xác nhận rằng ngay cả các bảng lồng nhau cũng tôn trọng các ngắt trang ... vấn đề đối với tôi là mac os vs ubuntu nhiều hơn ...
Petrov

Tôi đã gặp sự cố tương tự: bảng của tôi nằm trong một div có display: table-cell;áp dụng. Làm cho các kiểu đó @media only screencố định các ngắt trang. Nếu bạn không thể làm cho ngắt trang hoạt động, hãy cố gắng phân chia và chinh phục bằng cách loại bỏ một nửa CSS theo từng giai đoạn và xem liệu nó có hoạt động hay không.
Leslie Viljoen,

1

Tôi thấy giải pháp này vô lý, nhưng nó hoạt động rất tốt cho tôi :)

Tôi vừa đặt một cột sải hàng dài như thế này

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

và sau đó bàn sẽ không bị vỡ.


1

Một tùy chọn khác: đặt từng cái trvào riêng của nó tbodyvà sau đó áp dụng các quy tắc css của peage break cho tbody. Bảng hỗ trợ nhiều tbodys.

Một chút đánh dấu bổ sung, nhưng hiệu quả với tôi.


Tôi đã thử điều này trên một nhóm các phần tử tr - gói chúng trong các phần tử tbody riêng biệt - để cố gắng giữ các nhóm hàng nhất định lại với nhau. Nó không có tác dụng. Thực hiện phương pháp này mà không có "page-break-inside: tránh;" trên phần tử "tr" lại gây ra sự đảo ngược khi in dữ liệu trên đầu trang (hành vi "mặc định").
JosephK

Vâng, bây giờ tôi áp dụng cùng một quy tắc "page-break-inside: tránh" cho cả tbody và tr và td's: "tbody, tbody> tr, tbody> tr> td, tbody> tr> th {page-break-inside: tránh;} "có vẻ hoạt động trong hầu hết các tình huống.
Troy Morehouse

Cảm ơn, nhưng chỉ cần thử điều đó. Nó vẫn ngắt trang ở giữa các nhóm hàng trên bảng của tôi. Tôi cũng đã thử thêm một lớp vào tbody và css trên lớp đó với 'tránh' - không có hiệu lực. Tôi ước tôi biết điều này thực sự đang "làm" với quy tắc css - có thể một số cách để làm cho nó nghĩ rằng một nhóm các trs thực sự là 'một hàng' - nhưng vì việc tạo ra một chiều cao tr 2x + cũng phá vỡ nó, tôi đoán vậy không phải. Có thể ai đó sẽ tạo ra một giải pháp HTML sang PDF có thể sử dụng được trong 10 năm nữa, nhưng tôi nghĩ thay vào đó họ đang chờ đợi sự truyền dữ liệu thần kinh trực tiếp.
JosephK

1

Tôi đã giải quyết vấn đề bằng cách sử dụng kết hợp một số giải pháp được đề xuất.

Tôi đã bọc bảng của mình trong một div và xác định CSS sau đây.

.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;
    }

Cấu trúc bảng khi hoàn thành được định nghĩa như ví dụ sau:

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

Tôi không cần tạo bất kỳ div nào bên trong thẻ td hoặc th.

Những điều quan trọng mà tôi nhận thấy khi cố gắng giải quyết vấn đề:

  • Tbody phải được bao gồm trong bảng
  • Div phải có display: block
  • Khi một bảng không vừa với một trang, nó sẽ tự động di chuyển toàn bộ bảng sang trang tiếp theo (Tôi chưa thử cái này với các bảng lớn)
  • Nếu bạn chỉ xóa bộ chọn ".wrapping-div table" khỏi CSS, nó sẽ cho phép chia bảng thành hai trang, nhưng sẽ hiển thị chính xác, không ngắt một ô trong hai trang (nó giống như hành vi mặc định trên Word )

Tôi hi vọng cái này giúp được.



1

Để tránh ngắt trang, Chúng tôi có thể sử dụng tùy chọn css tránh ngắt trang.

tr { page-break-inside: avoid; }

Ngắt bất kỳ nội dung nào (Hình ảnh / Văn bản) và hiển thị nó ở trang tiếp theo

.sample-image { page-break-before: always; }

0

Bạn có đầu bảng không? và một thân bàn?

<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>

Đó là định dạng phù hợp của một bảng, trong khi hầu hết các trình duyệt không thể quan tâm hơn, các trình chuyển đổi như trình duyệt bạn đề cập có thể, nếu thiếu thẻ <tbody>hoặc <th>thẻ của bạn, tôi khuyên bạn nên thử thêm chúng trước.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.