0

0

利用 Paged.js 动态生成带页码的目录

聖光之護

聖光之護

发布时间:2025-11-28 15:12:22

|

1025人浏览过

|

来源于php中文网

原创

利用 paged.js 动态生成带页码的目录

本文详细介绍了如何使用 Paged.js 结合 JavaScript 动态生成 HTML 文档的目录(Table of Contents),并自动填充页码。通过定制 Paged.js 的处理器,在内容解析前构建目录结构,然后利用 CSS target-counter 功能实现页码的自动显示,解决了在打印布局中获取元素页码的挑战。

引言:动态目录与 Paged.js 的挑战

在将 HTML 内容转换为可打印的文档时,生成一个带有准确页码的动态目录是一个常见需求。传统的做法是手动更新页码,但这在内容变动时效率低下且易出错。使用像 Paged.js 这样的工具可以自动化这一过程,但直接通过 JavaScript 或 jQuery 访问 DOM 元素来获取其在最终打印布局中的页码并非易事,因为页码是 Paged.js 渲染引擎在布局阶段计算出来的。

本文将深入探讨如何利用 Paged.js 的强大功能,通过其生命周期钩子和 JavaScript 编程,实现一个完全动态且带有页码的目录生成方案。

核心机制:利用 Paged.js 的生命周期钩子

Paged.js 提供了一套生命周期钩子,允许开发者在文档处理的不同阶段介入。对于动态目录生成,最合适的钩子是 beforeParsed。在这个阶段,Paged.js 已经加载了 HTML 内容,但尚未进行布局和分页处理。这意味着我们可以在此时遍历文档中的标题元素,构建目录结构,并为它们添加必要的属性,为后续的页码显示做准备。

Paged.Handler 是 Paged.js 中用于扩展其功能的基类。通过创建一个继承自 Paged.Handler 的自定义类,并重写 beforeParsed 方法,我们可以在 Paged.js 开始解析内容之前执行自定义逻辑。

构建目录结构:JavaScript 实现

动态目录的构建主要通过一个 JavaScript 函数完成,该函数负责识别文档中的标题,为它们生成唯一的标识符(如果不存在),并构建一个链接到这些标题的目录列表。

HTML 基础结构

首先,我们需要在 HTML 文档中定义标题元素和目录的占位符。标题应具有清晰的结构,例如使用 <h1>, <h2> 等。目录占位符通常是一个空的 <ul> 或 <div>,它将通过 JavaScript 填充。

<!-- 文档中的标题 -->
<h1 id="pre-digital_era" class="chapter-title" data-title-level="1">
  前数字时代
</h1>
<p>此处是章节内容...</p>

<h2 id="digital_era" class="chapter-title" data-title-level="2">
  数字时代
</h2>
<p>此处是章节内容...</p>

<!-- 目录占位符 -->
<div id="my-toc-content">
  <!-- 动态生成的目录将插入到这里 -->
</div>

请注意,为标题添加 id 属性至关重要,因为目录中的链接(<a> 标签的 href 属性)将指向这些 ID。如果标题没有 ID,我们的 JavaScript 函数会为其自动生成。

createToc 函数详解

createToc 函数是实现动态目录的核心。它接收一个配置对象,包含内容的根元素、目录占位符的选择器以及标题元素的选择器数组。

function createToc(config) {
  const content = config.content; // 文档内容根元素
  const tocElementSelector = config.tocElement; // 目录占位符选择器
  const titleElementsSelectors = config.titleElements; // 标题元素选择器数组

  // 获取目录占位符元素,并创建一个无序列表作为目录容器
  let tocElementDiv = content.querySelector(tocElementSelector);
  let tocUl = document.createElement("ul");
  tocUl.id = "list-toc-generated";
  tocElementDiv.appendChild(tocUl);

  // 遍历所有指定标题元素,确保它们有ID并添加辅助类
  let tocElementNbr = 0;
  for (let i = 0; i < titleElementsSelectors.length; i++) {
    let titleHierarchy = i + 1; // 根据选择器数组的顺序确定层级
    let titleElements = content.querySelectorAll(titleElementsSelectors[i]);

    titleElements.forEach(function (element) {
      // 添加通用类和层级数据属性
      element.classList.add("title-element");
      element.setAttribute("data-title-level", titleHierarchy);

      // 如果元素没有ID,则生成一个唯一ID
      tocElementNbr++;
      if (element.id === "") {
        element.id = "title-element-" + tocElementNbr;
      }
    });
  }

  // 根据已处理的标题元素创建目录列表项
  let processedTocElements = content.querySelectorAll(".title-element");

  for (let i = 0; i < processedTocElements.length; i++) {
    let tocElement = processedTocElements[i];

    let tocNewLi = document.createElement("li");

    // 为目录列表项添加层级类
    tocNewLi.classList.add("toc-element");
    tocNewLi.classList.add(
      "toc-element-level-" + tocElement.dataset.titleLevel
    );

    // 复制标题元素的其他类到目录列表项(可选)
    let classTocElement = tocElement.classList;
    for (let n = 0; n < classTocElement.length; n++) {
      if (classTocElement[n] !== "title-element") {
        tocNewLi.classList.add(classTocElement[n]);
      }
    }

    // 创建链接,href指向标题ID,文本内容为标题内容
    tocNewLi.innerHTML =
      '<a href="#' + tocElement.id + '">' + tocElement.innerHTML + "</a>";
    tocUl.appendChild(tocNewLi);
  }
}

函数参数说明:

Imagine By Magic Studio
Imagine By Magic Studio

AI图片生成器,用文字制作图片

下载
  • config.content: Paged.js 传递的文档内容根元素,通常是 <body> 或其子元素。
  • config.tocElement: 目录占位符的 CSS 选择器,例如 "#my-toc-content"。
  • config.titleElements: 一个字符串数组,每个字符串是一个 CSS 选择器,用于匹配不同层级的标题元素,例如 ["h1", "h2", "h3"]。

工作流程:

  1. 初始化目录容器: 查找目录占位符,并在其中创建一个新的 <ul> 元素。
  2. 处理标题元素: 遍历 titleElementsSelectors 数组中的每个选择器。
    • 对于每个匹配的标题元素,为其添加 title-element 类和 data-title-level 属性,后者指示其在目录中的层级。
    • 如果标题元素没有 id 属性,则为其生成一个唯一的 ID。这是确保目录链接可用的关键。
  3. 生成目录列表: 再次遍历所有带有 title-element 类的标题元素。
    • 为每个标题创建一个 <li> 元素。
    • 根据标题的 data-title-level 属性为 <li> 添加层级类(例如 toc-element-level-1),便于 CSS 样式控制。
    • 创建一个 <a> 标签,其 href 属性设置为标题的 ID,其文本内容为标题的 HTML 内容。
    • 将 <li> 元素添加到目录 <ul> 中。

集成到 Paged.js 工作流

createToc 函数本身只是一个独立的 JavaScript 函数。为了让它在 Paged.js 处理文档时自动运行,我们需要将其封装在一个 Paged.Handler 中,并在 beforeParsed 钩子中调用它。

将以下代码添加到 HTML 文档的 <head> 部分,紧随 Paged.js 脚本之后:

<script type="text/javascript" src="path/to/paged.polyfill.js"></script>
<script>
  // ... createToc 函数定义 ...

  class CustomTocHandler extends Paged.Handler {
    constructor(chunker, polisher, caller) {
      super(chunker, polisher, caller);
    }

    // 在 Paged.js 解析内容之前执行
    beforeParsed(content) {
      createToc({
        content: content, // Paged.js 提供的文档内容根元素
        tocElement: "#my-toc-content", // 目录占位符的选择器
        titleElements: ["h1", "h2"], // 匹配 h1 和 h2 作为目录项
      });
    }
  }
  // 注册自定义处理器
  Paged.registerHandlers(CustomTocHandler);
</script>

在这个示例中,CustomTocHandler 是我们自定义的 Paged.js 处理器。在 beforeParsed 方法中,我们调用 createToc 函数,并传入 Paged.js 提供的 content 对象(代表了待处理的整个文档内容),以及目录占位符和标题选择器。

显示页码:CSS 与 target-counter

上述 JavaScript 代码完成了目录结构的构建,将标题链接到其对应的位置。然而,它并没有直接在目录中插入页码。页码的显示是 Paged.js 结合 CSS target-counter 功能来实现的。

target-counter() 是一个 CSS 函数,它允许你获取文档中某个元素在特定命名计数器(如 page 计数器)上的值。当与目录链接的 href 属性结合使用时,它就能显示链接目标元素的页码。

通常,你会在 CSS 中这样定义页码的显示:

@page {
  /* 定义页码计数器 */
  counter-increment: page;
  @bottom-right {
    content: counter(page); /* 在页面底部显示当前页码 */
  }
}

/* 为目录列表项添加页码 */
.toc-element a::after {
  content: target-counter(attr(href), page); /* 显示链接目标元素的页码 */
  float: right; /* 将页码浮动到右侧 */
  margin-left: 1em; /* 与标题文字保持距离 */
}

通过这种 CSS 规则,当 Paged.js 渲染文档时,它会自动计算每个标题的页码,并通过 target-counter(attr(href), page) 将其注入到目录 <a> 标签的 ::after 伪元素中。

注意事项与最佳实践

  1. HTML 结构清晰: 确保你的 HTML 标题结构(<h1>, <h2> 等)是语义化的,这有助于 createToc 函数准确识别目录项。
  2. ID 的唯一性: 尽管 createToc 会为没有 ID 的标题生成 ID,但最好在编写 HTML 时就为关键标题提供有意义且唯一的 ID,以提高可读性和维护性。
  3. CSS 选择器的准确性: 在 createToc 的 titleElements 配置中,使用精确的 CSS 选择器来匹配你希望包含在目录中的标题。
  4. Paged.js 依赖: 确保 Paged.js 库已正确加载到你的 HTML 文档中。
  5. 调试: 在开发过程中,可以使用浏览器的开发者工具检查生成的目录结构和 Paged.js 的控制台输出,以便调试任何问题。
  6. 样式定制: 利用 toc-element 和 toc-element-level-N 等类,你可以通过 CSS 对生成的目录进行精细的样式控制,例如缩进、字体大小等。

总结

通过 Paged.js 的 beforeParsed 钩子和自定义 JavaScript 函数,我们可以高效地动态生成 HTML 文档的目录。JavaScript 负责构建目录的结构和链接,而 Paged.js 结合 CSS target-counter 则负责在打印布局中自动填充正确的页码。这种方法不仅解决了手动更新页码的痛点,也使得内容更新和布局调整变得更加灵活和自动化,极大地提升了可打印文档的生成效率和用户体验。

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

WorkBuddy
WorkBuddy

腾讯云推出的AI原生桌面智能体工作台

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
jquery插件有哪些
jquery插件有哪些

jquery插件有jQuery UI、jQuery Validate、jQuery DataTables、jQuery Slick、jQuery LazyLoad、jQuery Countdown、jQuery Lightbox、jQuery FullCalendar、jQuery Chosen和jQuery EasyUI等。本专题为大家提供jquery插件相关的文章、下载、课程内容,供大家免费下载体验。

156

2023.09.12

jquery怎么操作json
jquery怎么操作json

操作的方法有:1、“$.parseJSON(jsonString)”2、“$.getJSON(url, data, success)”;3、“$.each(obj, callback)”;4、“$.ajax()”。更多jquery怎么操作json的详细内容,可以访问本专题下面的文章。

335

2023.10.13

jquery删除元素的方法
jquery删除元素的方法

jquery可以通过.remove() 方法、 .detach() 方法、.empty() 方法、.unwrap() 方法、.replaceWith() 方法、.html('') 方法和.hide() 方法来删除元素。更多关于jquery相关的问题,详情请看本专题下面的文章。php中文网欢迎大家前来学习。

406

2023.11.10

jQuery hover()方法的使用
jQuery hover()方法的使用

hover()是jQuery中一个常用的方法,它用于绑定两个事件处理函数,这两个函数将在鼠标指针进入和离开匹配的元素时执行。想了解更多hover()的相关内容,可以阅读本专题下面的文章。

515

2023.12.04

jquery实现分页方法
jquery实现分页方法

在jQuery中实现分页可以使用插件或者自定义实现。想了解更多jquery分页的相关内容,可以阅读本专题下面的文章。

312

2023.12.06

jquery中隐藏元素是什么
jquery中隐藏元素是什么

jquery中隐藏元素是非常重要的一个概念,在使用jquery隐藏元素之前,需要先了解css样式中关于元素隐藏的属性,比如display、visibility、opacity等属性。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

128

2024.02.23

jquery中什么是高亮显示
jquery中什么是高亮显示

jquery中高亮显示是指对页面搜索关键词时进行高亮显示,其实现办法:1、先获取要高亮显示的行,获取搜索的内容,再遍历整行内容,最后添加高亮颜色;2、使用“jquery highlight”高亮插件。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

183

2024.02.23

jQuery 正则表达式相关教程
jQuery 正则表达式相关教程

本专题整合了jQuery正则表达式相关教程大全,阅读专题下面的文章了解更多详细内容。

51

2026.01.13

C# ASP.NET Core微服务架构与API网关实践
C# ASP.NET Core微服务架构与API网关实践

本专题围绕 C# 在现代后端架构中的微服务实践展开,系统讲解基于 ASP.NET Core 构建可扩展服务体系的核心方法。内容涵盖服务拆分策略、RESTful API 设计、服务间通信、API 网关统一入口管理以及服务治理机制。通过真实项目案例,帮助开发者掌握构建高可用微服务系统的关键技术,提高系统的可扩展性与维护效率。

76

2026.03.11

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Sass 教程
Sass 教程

共14课时 | 0.9万人学习

Bootstrap 5教程
Bootstrap 5教程

共46课时 | 3.6万人学习

CSS教程
CSS教程

共754课时 | 42.5万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号