PAYATHON 2026

如何深入学习 paged.js 的 ESM 版本和 Hooks?

数据阿明

建议从官方文档、仓库 README 和 Hooks 实例入手,再用一个独立的打印页面练习 ESM 接入。这些资料涵盖了你遇到的两个难点,但不能据此认定存在一套形式与 learneleventy.dev 相同的完整课程。

优先阅读哪些资料?

  1. 官方文档目录:你已经掌握基础,可以重点阅读“How Paged.js works”,了解分页处理过程,再按需查阅 Generated Content、Named Page 和 Cross References。
  2. 官方仓库 README:重点阅读“NPM Module”和“Module”。前者展示如何显式调用 Previewer,后者介绍如何注册自定义 Handler。
  3. Handlers, Hooks and custom javascript:介绍 Hooks 的用途,包括处理打印链接、根据图片比例添加类名等实例。可以先复现一个例子,再改成符合自己需求的版本。

ESM 版本该怎么理解?

ESM 主要改变代码的导入和组织方式。常见的 polyfill 脚本接入方式会自动启动分页;使用模块接口时,可以导入 Previewer,自行决定处理哪些内容、使用哪些样式以及何时开始分页。官方 README 展示了这种调用方式,Previewer API 文档列出了 preview(content, stylesheets, renderTo) 的参数。

还要区分两个“模块”概念:ESM 指 JavaScript 模块机制;paged.js 文档中的功能模块通常由 Handler 组织,通过 Hooks 参与排版。两者有关联,但含义不同。

用最小示例理解 ESM 和 Hooks

这个练习假设你已有能够解析 npm 包并输出浏览器脚本的构建工具。先安装依赖:

npm install pagedjs

在测试页面中准备内容和输出容器:

<template id="print-source">
  <article>
    <h1>打印测试</h1>
    <p>先使用少量内容观察分页过程。</p>
  </article>
</template>

<div id="print-output"></div>

浏览器端模块代码如下。其中的 Previewer、Handler 和 registerHandlers 都是官方模块入口导出的接口:

import { Previewer, Handler, registerHandlers } from 'pagedjs';

class InspectPagination extends Handler {
  afterParsed(parsed) {
    console.log('Headings:', parsed.querySelectorAll('h1').length);
  }

  afterPageLayout(pageElement) {
    console.log('Page laid out:', pageElement);
  }

  afterRendered(pages) {
    console.log('Pagination finished:', pages.length);
  }
}

registerHandlers(InspectPagination);

async function renderPrintPreview() {
  const source = document.querySelector('#print-source');
  const target = document.querySelector('#print-output');
  const previewer = new Previewer();

  await previewer.preview(
    source.content.cloneNode(true),
    ['/print.css'],
    target
  );
}

renderPrintPreview().catch(console.error);

创建页面可访问的 /print.css:

@page {
  size: A4;
  margin: 20mm;
}

h1 {
  break-after: avoid;
}

先观察日志,再增加段落,直到内容跨页,对照“内容解析完成”“单页排版完成”和“整份内容分页完成”三个阶段。

import ... from 'pagedjs' 使用的是包名,浏览器通常需要构建工具或 import map 才能解析。11ty 项目中即使安装了 npm 依赖,生成后的页面也不一定能直接解析这个导入语句。上述代码应在浏览器环境运行,并在页面元素就绪后执行。

Hooks 适合做什么?

Hooks 允许你在分页处理的特定阶段执行代码,Handler 则集中定义这些处理方法。可以先掌握三个常用入口:

Hook执行阶段适合的练习
afterParsed(parsed)内容解析后、排版开始前检查标题、为元素添加打印所需的类名
afterPageLayout(pageElement, page, breakToken)单页排版完成后查看当前页的 DOM,定位分页问题
afterRendered(pages)所有页面排版完成后统计页数、执行最终检查

Hook 方法也可以返回 Promise,让处理流程等待异步任务。具体触发阶段和参数应根据所用版本核对。官方 Hooks 文档解释了这些机制,也说明该页文档仍有待补充。

需要改变内容尺寸或结构的操作,尽量放在排版开始前。分页结束后再插入大段内容或改变字体尺寸,可能让已计算的分页结果失效。

如何接入 11ty 工作流?

建议先让 11ty 从 Markdown 生成一个独立的打印 HTML 页面,再在该页面加载 paged.js 和打印样式。数字花园页面继续使用适合屏幕阅读的模板,两种输出复用内容即可。

学习时可以依次手动调用一次 preview(),注册一个只输出日志的 Handler,再加入一个确实需要的内容处理操作。等这条流程稳定后,再接入 PDF 导出。

分页预览和文件导出也有区别:preview() 负责生成分页结果,不会直接保存 PDF。演示文稿的页面结构和交互需要按目标形式另行设计,不能仅靠这段分页代码完成。

备注:内容仅供参考。