TCPDF 如何将 HTML 表格分页打印?

7
我使用TCPDF来输出一个HTML表格,在我的示例中,这不是我唯一需要修改的表格,因此我需要一些规则来渲染我的页面。目前,TCPDF对我来说似乎是一个强大的库,所以我希望不要尝试另一个库。
我的问题是,我需要在每个新页面上添加表头,但我还有其他信息要写入到这个PDF中,这些信息不能有表头,因此我不能使用TCPDF中重写标题方法的方式。
<table border="0" cellspacing="0" cellpadding="0" align="center" width="100%" ><tr><td><table border="0" cellspacing="0" cellpadding="3" align="left" width="100%" ><tr><td class="TableHeader"  width="5%" style="padding: 5px; border-top: 1px solid #000000; border-left: 1px solid #000000; border-bottom: 1px solid #E4E9EC;" >Nr.</td><td class="TableHeader" width="40%" style=" padding: 5px; border-top: 1px solid #000000; border-bottom: 1px solid #E4E9EC;" >Denumire</td><td class="TableHeader" width="20%" align="left" style=" padding: 5px; border-top: 1px solid #000000; border-bottom: 1px solid #E4E9EC;" >Cod</td><td class="TableHeader" width="10%" align="center" style=" padding: 5px; border-top: 1px solid #000000; border-bottom: 1px solid #E4E9EC;" >Cant.</td><td class="TableHeaderLast" align="right" width="13%" style=" padding: 5px; border-top: 1px solid #000000; border-bottom: 1px solid #E4E9EC;" >Pret unitar<br />fara TVA (RON)</td><td class="TableHeaderLast" align="right" width="13%" style=" padding: 5px; border-bottom: 1px solid #E4E9EC; border-top: 1px solid #000000; border-right: 1px solid #000000;" >Pret total<br />fara TVA (RON)</td></tr></table></td></tr></table><table border="0" cellspacing="0" cellpadding="0" align="center" width="100%" id="Container"><tr><td><table border="0" cellspacing="0" cellpadding="3" align="left" width="100%" ><tr><td class="TableHeader"  width="5%" style="padding: 5px; border-left: 1px solid #000000;" >&nbsp;</td><td class="TableHeader" width="40%" style=" padding: 5px;" >&nbsp;</td><td class="TableHeader" width="20%" style=" padding: 5px;" >&nbsp;</td><td class="TableHeader" width="10%" style=" padding: 5px;" >&nbsp;</td><td class="TableHeaderLast" align="right" width="13%" style=" padding: 5px;" >&nbsp;</td><td class="TableHeaderLast" align="right" width="13%" style=" padding: 5px; border-right: 1px solid #000000;" >&nbsp;</td></tr><tr style="border-bottom: 1px solid #ccc"><td class="TableRow" style="padding: 5px; border-bottom: 1px solid #E4E9EC; border-left: 1px solid #000000; ">1</td><td class="TableRow" style="padding: 5px; border-bottom: 1px solid #E4E9EC;"><b>sectiune1</b></td><td class="TableRow" colspan="5" style="padding: 5px; border-bottom: 1px solid #E4E9EC; border-right: 1px solid #000000;">&nbsp;</td></tr><tr style="border-bottom: 1px solid #ccc"><td class="TableRow" style="padding: 5px; border-left: 1px solid #000000;border-bottom: 1px solid #E4E9EC; ">1.1</td><td class="TableRow" style="padding: 5px;border-bottom: 1px solid #E4E9EC; ">UNI-Cazan mixt AIREX 25 2S BICOMB MODUL  </td><td class="TableRow" align="left" style="padding: 5px;border-bottom: 1px solid #E4E9EC; ">94456&nbsp;</td><td class="TableRow"  align="center" style="padding: 5px;border-bottom: 1px solid #E4E9EC;">99999</td><td class="TableRow" align="right" style="padding: 5px;border-bottom: 1px solid #E4E9EC; ">24.623,00</td><td class="TableRow" align="right"  style="padding: 5px;  border-right: 1px solid #000000;border-bottom: 1px solid #E4E9EC;">2.462.275.377,00</td></tr><tr style="border-bottom: 1px solid #ccc"><td class="TableRow" style="padding: 5px; border-left: 1px solid #000000;border-bottom: 1px solid #E4E9EC; ">1.2</td><td class="TableRow" style="padding: 5px;border-bottom: 1px solid #E4E9EC; ">UNI-Cazan mixt AIREX 25 2S BICOMB MODUL  </td><td class="TableRow" align="left" style="padding: 5px;border-bottom: 1px solid #E4E9EC; ">94456&nbsp;</td><td class="TableRow"  align="center" style="padding: 5px;border-bottom: 1px solid #E4E9EC;">99999</td><td class="TableRow" align="right" style="padding: 5px;border-bottom: 1px solid #E4E9EC; ">24.623,00</td><td class="TableRow" align="right"  style="padding: 5px;  border-right: 1px solid #000000;border-bottom: 1px solid #E4E9EC;">2.462.275.377,00</td></tr><tr style="border-bottom: 1px solid #ccc"><td class="TableRow" style="padding: 5px; border-bottom: 1px solid #000; border-left: 1px solid #000000; ">&nbsp;</td><td class="TableRow" width="40%" style="padding: 5px; border-bottom: 1px solid #000; "><b> TOTAL sectiune1:</b></td><td class="TableRow" style="padding: 5px; border-bottom: 1px solid #000; "> &nbsp;</td><td class="TableRow" style="padding: 5px; border-bottom: 1px solid #000; "> &nbsp;</td><td class="TableRowLast" colspan="2" align="right" style="padding: 5px; border-bottom: 1px solid #000; border-right: 1px solid #000000; "><b>4.924.550.754,00</b></td></tr><tr style="border-bottom: 1px solid #ccc"><td class="TableRow" style="padding: 5px; border-top: 1px solid #000; border-bottom: 1px solid #000; ">&nbsp;</td><td class="TableRow" style="padding: 5px; border-top: 1px solid #000; border-bottom: 1px solid #000;">&nbsp;</td><td class="TableRow" colspan="5" style="padding: 5px; border-top: 1px solid #000; border-bottom: 1px solid #000; ">&nbsp;</td></tr><tr style="border-bottom: 1px solid #ccc"><td class="TableRow" style="padding: 5px; border-top: 1px solid #000; border-bottom: 1px solid #E4E9EC; border-left: 1px solid #000000; ">2</td><td class="TableRow" style="padding: 5px; border-bottom: 1px solid #E4E9EC; border-top: 1px solid #000;"><b>sectiune2</b></td><td class="TableRow" colspan="5" style="padding: 5px; border-bottom: 1px solid #E4E9EC; border-right: 1px solid #000000; border-top: 1px solid #000;">&nbsp;</td></tr><tr style="border-bottom: 1px solid #ccc"><td class="TableRow" style="padding: 5px; border-left: 1px solid #000000;border-bottom: 1px solid #E4E9EC; ">2.1</td><td class="TableRow" style="padding: 5px;border-bottom: 1px solid #E4E9EC; ">ICI-Cazan condensatie MONOLITE 75-JB</td><td class="TableRow" align="left" style="padding: 5px;border-bottom: 1px solid #E4E9EC; ">81020076&nbsp;</td><td class="TableRow"  align="center" style="padding: 5px;border-bottom: 1px solid #E4E9EC;">99999</td><td class="TableRow" align="right" style="padding: 5px;border-bottom: 1px solid #E4E9EC; ">34.719,00</td><td class="TableRow" align="right"  style="padding: 5px;  border-right: 1px solid #000000;border-bottom: 1px solid #E4E9EC;">3.471.865.281,00</td></tr><tr style="border-bottom: 1px solid #ccc"><td class="TableRow" style="padding: 5px; border-bottom: 1px solid #000; border-left: 1px solid #000000; ">&nbsp;</td><td class="TableRow" width="40%" style="padding: 5px; border-bottom: 1px solid #000; "><b> TOTAL sectiune2:</b></td><td class="TableRow" style="padding: 5px; border-bottom: 1px solid #000; "> &nbsp;</td><td class="TableRow" style="padding: 5px; border-bottom: 1px solid #000; "> &nbsp;</td><td class="TableRowLast" colspan="2" align="right" style="padding: 5px; border-bottom: 1px solid #000; border-right: 1px solid #000000; "><b>3.471.865.281,00</b></td></tr><tr style="border-bottom: 1px solid #ccc"><td class="TableRow" style="padding: 5px; border-top: 1px solid #000; border-bottom: 1px solid #000; ">&nbsp;</td><td class="TableRow" style="padding: 5px; border-top: 1px solid #000; border-bottom: 1px solid #000;">&nbsp;</td><td class="TableRow" colspan="5" style="padding: 5px; border-top: 1px solid #000; border-bottom: 1px solid #000; ">&nbsp;</td></tr><tr><td class="TableTotal"  style=" padding: 5px; border-left: 1px solid #000000;"></td><td colspan="3" class="TableTotal"  style=" padding: 5px; " ><b>Total sectiune1:</b></td><td align="right" class="TableTotal" style=" padding: 5px; " ><b>&nbsp;</b></td><td class="TableTotal" align="right" style=" padding: 5px; border-right: 1px solid #000000;" ><b>4.924.550.754,00 </b></td></tr><tr><td class="TableTotal"  style=" padding: 5px; border-left: 1px solid #000000;"></td><td colspan="3" class="TableTotal"  style=" padding: 5px; " ><b>Total sectiune2:</b></td><td align="right" class="TableTotal" style=" padding: 5px; " ><b>&nbsp;</b></td><td class="TableTotal" align="right" style=" padding: 5px; border-right: 1px solid #000000;" ><b>3.471.865.281,00 </b></td></tr><tr><td class="TableTotal"  style=" padding: 5px; border-left: 1px solid #000000;border-top: 1px solid #E4E9EC; "></td><td colspan="4" class="TableTotal"  style=" padding: 5px;border-top: 1px solid #E4E9EC; " ><b>Total oferta (RON):</b></td><td colspan="2" align="right" class="TableTotal" style=" padding: 5px; border-right: 1px solid #000000;border-top: 1px solid #E4E9EC; " ><b>8.396.416.035,00 </b></td></tr><tr><td class="TableTotal"  style=" padding: 5px; border-left: 1px solid #000000;border-bottom: 1px solid #000000;"></td><td colspan="4" class="TableTotal"  style=" padding: 5px;border-bottom: 1px solid #000000;" ><b>Total oferta (RON cu TVA inclus):</b></td><td colspan="2" align="right" class="TableTotal" style=" padding: 5px; border-right: 1px solid #000000;border-bottom: 1px solid #000000;" ><b>10.411.555.883,40 </b></td></tr></table></td></tr></table>

我想到了以下解决方案:如果我能够将这个HTML分成行,并逐行写入PDF,那么当我在页脚上书写时就可以回滚,然后添加新页面,但有一个主要问题,我会得到各种警告,因为HTML表格标记没有关闭。 以下是我的代码:
$pdf->setAutoPageBreak(false);
$pdf->startTransaction();
$html = new simple_html_dom();
$html->load($data);
$single = $html->find('#Container', 0);
if($single){

 $rows = $single->getElementsByTagName('tr');
 $rows = $rows[0]->getElementsByTagName('tr');

 if($rows)
   for($i=1;$i<(count($rows)-1);$i++){
     $pdf->writeHTMLCell($w=0, $h=0, $x='', $y='', '<table>', $border=0, $ln=1, $fill=0, $reseth=true, $align='', $autopadding=false);
     $pdf->writeHTMLCell($w=0, $h=0, $x='', $y='', $rows[$i]->outertext, $border=0, $ln=1, $fill=0, $reseth=true, $align='', $autopadding=false);
     $pdf->writeHTMLCell($w=0, $h=0, $x='', $y='', '</table>', $border=0, $ln=1, $fill=0, $reseth=true, $align='', $autopadding=false);

   if ($pdf->getY() > $pdf->getPageHeight() - 30) {
       $pdf->rollbackTransaction(true);
       $pdf->AddPage();
       $pdf->writeHTMLCell($w=0, $h=0, $x='', $y='', '<table>', $border=0, $ln=1, $fill=0, $reseth=true, $align='', $autopadding=false);
       $pdf->writeHTMLCell($w=0, $h=0, $x='', $y='', $rows[$i]->outertext, $border=0, $ln=1, $fill=0, $reseth=true, $align='', $autopadding=false);
       $pdf->writeHTMLCell($w=0, $h=0, $x='', $y='', '</table>', $border=0, $ln=1, $fill=0, $reseth=true, $align='', $autopadding=false);
        }
    }
   }


    $pdf->commitTransaction();
    $pdf->setAutoPageBreak(true, 30);

我看了一下这两篇文章,也许有人会觉得它们很有用: 使用multicell进行分页另一种使用multicell进行分页的方法。我认为这两个例子很值得作为解决逻辑的示例,但是tcpdf使用的方法对我来说有点奇怪。

嗨@decebal,我能拿到你解决这个问题的代码吗? - Abdullah
@Abdullah 不确定你的意思?如果你是在请求使用上面那个的许可,你不需要它,随意使用即可。 - Decebal
我只需要翻译文本,不需要解决方案文件。 - Abdullah
2个回答

6
我认为你的解决方案很好。我能想到的唯一另一种方法是使用固定宽度的多单元格,这可能会很麻烦,但可以给您静态列宽。
然而,我注意到了几个问题:
  1. 您的事务将整个文档包装起来,回滚应将文档重置为空。
  2. 您的警告可能是由于传递了不可呈现的部分html代码导致的writeHTMLCell。(您仅通过<table>或</table>传递它们时,无法呈现)
  3. 如果在每行中包装标签,则列将不对齐。最好的选择是在该页面上用table块包装行。 尝试这些更改并告诉我进展如何。
    $pdf->setAutoPageBreak(false);
    //$pdf->startTransaction(); // Moved
    $html = new simple_html_dom();
    $html->load($data);
    $single = $html->find('#Container', 0);
    if($single){
    
        $rows = $single->getElementsByTagName('tr');
        $rows = $rows[0]->getElementsByTagName('tr');
    
        if($rows) {
            $pdf->startTransaction(); // Start transaction only because we may need it
            // Header for html, this starts the html and can optionally insert the header row as the first row on every new page.
            $html_header = '<tr><td>Name</td><td>Age</td></tr>'; 
            $html_buffer = '<table>'.$html_header;
            for($i=1;$i<(count($rows)-1);$i++){
                $pdf->writeHTMLCell($w=0, $h=0, $x='', $y='', $html_buffer.$rows[$i]->outertext.'</table>', $border=0, $ln=1, $fill=0, $reseth=true, $align='', $autopadding=false);
    
                if ($pdf->getY() < ($pdf->getPageHeight() - 30)) { // Note the less-than operator
                    // We might be able to add some more text, so undo that
                    $pdf->rollbackTransaction(true);
                    // And store the html
                    $html_buffer .= $rows[$i]->outertext;
                }else{
                    // We exceeded our limit
                    $pdf->rollbackTransaction(true);
                    // Write last known good table
                    $pdf->writeHTMLCell($w=0, $h=0, $x='', $y='', $html_buffer.'</table>', $border=0, $ln=1, $fill=0, $reseth=true, $align='', $autopadding=false);
                    // Add a new page
                    $pdf->AddPage();
                    // End this transaction
                    $pdf->commitTransaction();
                    // Start a new transaction
                    $pdf->startTransaction();
                    // Reset html buffer
                    $html_buffer = '<table>'.$html_header;
                    // Add line we couldn't fit on last page to html buffer
                    $html_buffer .= $rows[$i]->outertext;
                }
            }
            // There is still information in our buffer and it fits on a single page
            $pdf->writeHTMLCell($w=0, $h=0, $x='', $y='', $html_buffer.'</table>', $border=0, $ln=1, $fill=0, $reseth=true, $align='', $autopadding=false);
            // Final commit
            $pdf->commitTransaction(); 
        }
    }
    $pdf->setAutoPageBreak(true, 30);
    

    这个代码将页面上的所有内容包装在一个表格块中,以便页面上的列会对齐(但是从页面到页面可能仍然有所不同)。另外,我已经为你提供了在每个新页面上添加自己标题的功能,就像你想要的那样。只需将$html_header更改为你自己的标题行代码即可。

    当你说TCPDF可能会让人困惑时,你是对的,但它也非常强大,一旦你掌握了它,你可以创建一些非常漂亮的文档。


我进行了以下修改:将“<table>”替换为$table_tag,因为我需要一些样式,否则它的工作非常出色,感谢你 :) - Decebal
我遇到了一些其他问题,所以我需要添加这个if(!strpos($rows[$i-1]->outertext,$rows[$i]->outertext)) $html_buffer .= $rows[$i]->outertext; - Decebal

5

前往TCPDF并选择Example 48,您将看到一个带有<thead>元素的示例。


1
应该读取 "thead" 元素。我还发现 HTML 应该经过验证才能正常工作。 - Burton Kent

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接