页眉、页脚与多页文档
一页往往不够用。在本教程中,你将编写一份能自行扩展到三页的文档。你还会为每一页添加一个重复出现的页眉,以及一个显示页码的页脚。
你将构建什么
标题为“你将构建什么”的章节你将编写一个脚本 01-multipage.php。它会生成一份三页的旅行日志,输出为
PDF(Portable Document Format,可移植文档格式)文件:
- 日志条目会自动在页面之间流动。你从不需要指定某一页在哪里结束;这由引擎来决定。
- 页眉是页面顶部的一条区域,会在每一页上重复出现。你的页眉显示文档标题。
- 页脚是与之对应的底部区域。你的页脚以
1 / 3、2 / 3、3 / 3的形式显示页码。
所有内容都仅依靠 nextpdf/core 包运行:不需要字体文件,不需要额外扩展,
也不需要联网。
第 1 步:构建三页日志
标题为“第 1 步:构建三页日志”的章节这个脚本靠两个概念完成全部工作。
第一个是自动分页。引擎在写入文本时,会跟踪一个光标:即页面上下一行将要落下的位置。setAutoPageBreak(true, margin: 25) 告诉引擎留意这个光标。当它接近底部边缘、距离在 25 点(约三分之一英寸)以内时,引擎就会关闭当前页并另起崭新的一页。
第二个是页面上的固定元素:页眉和页脚。你只需在第一页之前描述它们一次。
setHeaderData() 会为顶部区域记录标题和一段简短描述。字体与边距的调用则决定字样以及与页面边缘的距离。此后,引擎会在它创建的每一页上绘制这些元素,包括它自行添加的页面。
在你的项目文件夹中创建 01-multipage.php:
<?php
declare(strict_types=1);
require __DIR__ . '/vendor/autoload.php';
use NextPDF\Core\Document;
// Make sure the output folder exists next to this script.@mkdir(__DIR__ . '/out');
$document = Document::createStandalone();$document->setTitle('NextPDF Travel Journal');
// Configure the header and footer BEFORE the first page.// The engine repeats them on every page for you.$document->setHeaderData(title: 'NextPDF Travel Journal', description: 'A multi-page tutorial document');$document->setHeaderFont('helvetica', 10);$document->setHeaderMargin(5);$document->setFooterFont('helvetica', 8);$document->setFooterMargin(10);
// Turn on automatic page breaks. When the text cursor gets within// 25 points of the bottom edge, the engine starts a new page.$document->setAutoPageBreak(true, margin: 25);
$document->addPage();
$document->setFont('helvetica', 'B', 18);$document->cell(0, 12, 'Travel journal: three days on the coast', newLine: true);$document->ln(5);
$days = [ 1 => 'We followed the shoreline north and counted seventeen lighthouses.', 2 => 'Rain moved in before noon, so we sketched the harbor from a cafe window.', 3 => 'On the last morning the fog lifted and the whole bay turned silver.',];
foreach ($days as $day => $highlight) { $document->setFont('helvetica', 'B', 14); $document->cell(0, 10, "Day {$day}", newLine: true);
$document->setFont('helvetica', '', 11); for ($entry = 1; $entry <= 12; $entry++) { $text = "Entry {$entry} of day {$day}. {$highlight} " . 'The trail hugged the cliffs for most of the afternoon, and every ' . 'turn opened another view of the water. We stopped often to take ' . 'notes, compare maps, and argue happily about where to eat dinner. ' . 'By the time we reached the guesthouse, our boots were soaked and ' . 'our notebooks were full.'; $document->multiCell(0, 7, $text); $document->ln(3); } $document->ln(5);}
// Ask the engine how many pages the layout produced, then save.$pages = $document->getNumPages();$document->save(__DIR__ . '/out/travel-journal.pdf');
echo "Wrote out/travel-journal.pdf with {$pages} pages\n";用 php 01-multipage.php 运行它。脚本会打印出一行:
Wrote out/travel-journal.pdf with 3 pages打开 out/travel-journal.pdf 并滚动浏览。标题区域位于全部三页的顶部,
页码则在右下角依次递增。
刚刚发生了什么
标题为“刚刚发生了什么”的章节写入循环从未提到页面。它用 cell() 写出每一天的标题,cell() 会把一行放进一个不可见的方框里。它用 multiCell() 写出各条目,multiCell() 会把长文本按需换行到任意多行。三十六个条目无法容纳在一页上,因此自动分页触发了两次。日志正是这样变成了恰好三页。
页眉和页脚是在第一次调用 addPage() 之前配置的。这个顺序很重要:已经绘制好的页面,之后就不会再更新。先把这些固定元素配置好,每一页才会保持一致。
你从未亲手绘制页码。页脚默认就会打印它;你只是选择了它的字体以及与页面边缘的距离。引擎在写入各页时,还无法知道最终的页数。因此它会在每个页脚里留下一个占位符,等你保存时再填入真正的总数。
还有两个小细节让脚本更加完整。@mkdir 会创建 out 文件夹,而 @ 符号能在该文件夹已存在时让 PHP 保持安静。getNumPages() 会向引擎询问版面生成了多少页,这样最终的消息就能报告真实的页数。
如果出了问题
标题为“如果出了问题”的章节- 如果
require那一行报出 “failed to open stream” 错误,说明脚本找不到vendor/autoload.php。请在包含vendor/的项目文件夹内运行它。 - 所有内容都挤在一页上,而且文本末尾被截断了?那说明自动分页被关闭了。
请保留
setAutoPageBreak(true, margin: 25)这一行,并确保它位于写入循环的上方。 - 字体族名拼写错误会抛出一个异常,其中会指出它找不到的那个字体。请检查
helvetica的拼写,遇到更深层的字体问题可参阅 字体与标记。 - 其他任何情况下,疑难排解中心会把症状对应到原因,而错误参考则解释了引擎的通用异常,以及如何从每一种异常中恢复。
下一步
标题为“下一步”的章节现在你的文档可以扩展到任意长度,同时仍然显得完整。在 下一篇教程中,你将用 HTML(Hypertext Markup Language,超文本标记语言)编写内容,并让引擎把它转换成页面。
当你想对今天这些主题有更精细的控制时,有两篇 recipe(示例)讲得更深入:
- 构建多页文档详细讲解了分页, 包括其各种边界情况。
- 添加重复的页眉与页脚会逐一介绍每一项页眉和页脚设置,包括如何将它们关闭。