0

0

使用 paged.js 高效构建可打印HTML的动态目录

霞舞

霞舞

发布时间:2025-11-28 12:01:37

|

163人浏览过

|

来源于php中文网

原创

使用 paged.js 高效构建可打印html的动态目录

本教程旨在指导开发者如何利用 paged.js 库为可打印的 HTML 文档动态生成一个结构清晰的目录。文章将详细介绍如何通过 JavaScript 遍历文档中的标题元素、生成锚点链接,并将其集成到 paged.js 的处理流程中,从而在打印输出时实现一个功能完善、自动更新的目录,无需直接通过 JavaScript 获取页面号。

在构建可打印的 HTML 文档时,尤其对于长篇内容,一个带有章节页码的目录是必不可少的。传统的做法可能涉及在 JavaScript 中尝试获取特定元素所在的页码,但由于页码是打印布局的产物,并非 DOM 元素的固有属性,这种方法往往难以实现。paged.js 提供了一种优雅的解决方案,允许我们在其渲染流程中动态构建目录,从而间接实现页码关联的效果。

核心原理

paged.js 的核心在于将 HTML 内容流式地分页,并应用 CSS 打印样式。为了生成动态目录,我们不需要直接在 JavaScript 中计算页码。相反,我们可以在 paged.js 开始分页之前,通过 JavaScript 遍历文档中的所有章节标题,为它们创建唯一的 ID,并在目录区域生成指向这些 ID 的锚点链接。当 paged.js 完成分页并生成打印输出时,这些锚点链接将自然地指向其对应的章节起始位置,而打印机或 PDF 阅读器则会显示这些章节所在的实际页码。

paged.js 提供了处理程序(Handlers)机制,允许我们在其处理生命周期的不同阶段注入自定义逻辑。对于目录生成,beforeParsed 钩子是理想的选择,因为它在 HTML 内容被解析但尚未进行分页布局之前执行。

立即学习前端免费学习笔记(深入)”;

准备您的 HTML 结构

首先,确保您的 HTML 文档包含清晰的章节标题和目录的占位符。

  1. 章节标题: 使用语义化的标题标签(如

    ,

    ,

    等)来标识您的章节。为确保锚点链接的正确性,这些标题需要有唯一的 id 属性。如果标题本身没有 id,我们将通过 JavaScript 动态添加。

  2. 目录占位符: 在您希望目录出现的位置创建一个空的容器元素,例如一个 div 或 ul,并为其指定一个唯一的 id。

示例 HTML 结构:




  可打印文档
  
  
  



  
  

目录

数字时代前夕

这是数字时代前夕的相关内容...

早期计算机

早期计算机的发展历史...

魔珐星云
魔珐星云

无需昂贵GPU,一键解锁超写实/二次元等多风格3D数字人,跨端适配千万级并发的具身智能平台。

下载

数字时代

这是数字时代的相关内容...

互联网革命

互联网如何改变世界...

动态生成目录的 JavaScript 逻辑

接下来,我们将编写一个 JavaScript 函数来遍历文档中的标题,并根据它们生成目录项。

/**
 * 动态生成目录
 * @param {object} config - 配置对象
 * @param {HTMLElement} config.content - 文档内容根元素
 * @param {string} config.tocElement - 目录容器的选择器
 * @param {string[]} config.titleElements - 标题元素的选择器数组,按层级顺序
 */
function createToc(config) {
  const content = config.content; // 文档内容根元素
  const tocElementSelector = config.tocElement; // 目录容器选择器
  const titleElementsSelectors = config.titleElements; // 标题元素选择器数组

  // 查找目录容器,并创建或获取 ul 元素
  let tocContainer = content.querySelector(tocElementSelector);
  if (!tocContainer) {
    console.warn(`目录容器 ${tocElementSelector} 未找到.`);
    return;
  }
  let tocUl = tocContainer.querySelector("#list-toc-generated");
  if (!tocUl) {
    tocUl = document.createElement("ul");
    tocUl.id = "list-toc-generated";
    tocContainer.appendChild(tocUl);
  } else {
    // 清空现有目录,防止重复生成
    tocUl.innerHTML = '';
  }

  let tocElementNbr = 0; // 用于生成唯一 ID 的计数器

  // 1. 遍历所有标题元素,添加必要属性
  for (let i = 0; i < titleElementsSelectors.length; i++) {
    let titleHierarchy = i + 1; // 标题层级 (1, 2, 3...)
    let currentLevelTitles = content.querySelectorAll(titleElementsSelectors[i]);

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

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

  // 2. 遍历所有标记为 "title-element" 的元素,创建目录列表项
  let tocElements = content.querySelectorAll(".title-element");

  for (let i = 0; i < tocElements.length; i++) {
    let tocElement = tocElements[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]);
      }
    }

    // 创建锚点链接
    tocNewLi.innerHTML = `${tocElement.innerHTML}`;
    tocUl.appendChild(tocNewLi);
  }
}

代码解释:

  • createToc 函数接收一个配置对象,包含文档内容根元素、目录容器选择器和标题元素选择器数组。
  • 它首先查找目录容器,并确保其中有一个 ID 为 list-toc-generated 的
      元素用于存放目录项。
  • 接着,它分两步处理:
    1. 标记标题: 遍历 titleElementsSelectors 中定义的每个标题选择器。对于匹配到的每个标题元素,它会添加 title-element 类和 data-title-level 数据属性来指示其层级。如果标题没有 id,它会为其生成一个唯一的 ID。
    2. 构建目录: 再次遍历所有带有 title-element 类的元素。为每个元素创建一个
    3. 标签,并生成一个 锚点链接,其 href 指向标题的 id,文本内容为标题的 innerHTML。最后,将
    4. 添加到目录
        中。

集成到 paged.js 工作流

为了让 createToc 函数在 paged.js 处理文档时自动执行,我们需要创建一个 Paged.Handler 并将其注册到 paged.js。

将以下代码添加到您的 HTML 文档的

部分,紧随 paged.js 脚本之后:

代码解释:

  • 我们定义了一个名为 CustomTocHandler 的类,它继承自 Paged.Handler。
  • 在 CustomTocHandler 中,我们重写了 beforeParsed 方法。这个方法会在 paged.js 解析完所有 HTML 内容,但尚未开始计算页面布局之前被调用。
  • beforeParsed 方法接收一个 content 参数,它是当前文档内容的根元素,我们可以用它来查询和操作 DOM。
  • 在 beforeParsed 中,我们调用之前定义的 createToc 函数,并传入必要的配置。
    • content: 直接使用 paged.js 提供的 content 元素。
    • tocElement: 指定您的目录容器的选择器。
    • titleElements: 指定您希望包含在目录中的标题元素选择器数组。可以根据实际需求调整,例如 ["h1", "h2", "h3"] 或者更具体的 [".chapter-title", "article h2"]。
  • 最后,通过 Paged.registerHandlers(CustomTocHandler) 将您的处理程序注册到 paged.js。

注意事项与最佳实践

  1. CSS 样式: 生成的目录只包含基本的 HTML 结构。您需要编写 CSS 样式来美化目录,例如添加缩进以体现层级关系、调整字体大小和颜色等。
    #my-toc-content ul {
      list-style: none;
      padding-left: 0;
    }
    .toc-element-level-1 {
      margin-left: 0;
      font-weight: bold;
    }
    .toc-element-level-2 {
      margin-left: 20px;
    }
    .toc-element-level-3 {
      margin-left: 40px;
      font-style: italic;
    }
    /* 您也可以使用 CSS counters 来添加页码,paged.js 会自动处理 */
    /* 例如,在 @page 规则中设置页码 */
    @page {
      @bottom-right {
        content: counter(page);
      }
    }
  2. 选择器精度: titleElements 数组中的选择器应尽可能精确,以避免将不希望出现在目录中的元素包含进来。例如,如果您只想将文章主体内的

    包含进来,可以使用 article h2 而不是简单的 h2。

  3. ID 管理: createToc 函数已经包含了为没有 id 的标题自动生成 id 的逻辑,这增强了其健壮性。但如果您的标题本身就有稳定的 id,最好保持它们。
  4. 性能: 对于非常大的文档,querySelectorAll 操作可能会有性能开销。在大多数情况下,这种开销可以忽略不计,但如果遇到性能问题,可以考虑优化 DOM 查询。
  5. 可访问性: 确保生成的目录在语义上是正确的,并考虑到可访问性。例如,使用
    • 标签来表示列表结构。
    • 页码显示: 再次强调,paged.js 会通过 CSS 的 @page 规则和 counter(page) 功能在页眉或页脚自动添加页码。我们这里构建的 JavaScript 目录是基于锚点链接,它确保了目录项能够正确地导航到对应的章节,而实际的页码会在打印时由 paged.js 和浏览器/打印机引擎负责呈现。

总结

通过 paged.js 的处理程序机制,我们可以优雅地解决为可打印 HTML 文档动态生成目录的问题。这种方法避免了在 JavaScript 中复杂地计算页码,而是利用了 paged.js 在分页前对 DOM 进行操作的能力,通过锚点链接实现了目录与章节的关联。结合适当的 CSS 样式,您可以为您的打印输出提供一个专业、功能完善且易于导航的动态目录。

相关文章

HTML速学教程(入门课程)
HTML速学教程(入门课程)

HTML怎么学习?HTML怎么入门?HTML在哪学?HTML怎么学才快?不用担心,这里为大家提供了HTML速学教程(入门课程),有需要的小伙伴保存下载就能学习啦!

下载

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

相关专题

更多
js获取数组长度的方法
js获取数组长度的方法

在js中,可以利用array对象的length属性来获取数组长度,该属性可设置或返回数组中元素的数目,只需要使用“array.length”语句即可返回表示数组对象的元素个数的数值,也就是长度值。php中文网还提供JavaScript数组的相关下载、相关课程等内容,供大家免费下载使用。

553

2023.06.20

js刷新当前页面
js刷新当前页面

js刷新当前页面的方法:1、reload方法,该方法强迫浏览器刷新当前页面,语法为“location.reload([bForceGet]) ”;2、replace方法,该方法通过指定URL替换当前缓存在历史里(客户端)的项目,因此当使用replace方法之后,不能通过“前进”和“后退”来访问已经被替换的URL,语法为“location.replace(URL) ”。php中文网为大家带来了js刷新当前页面的相关知识、以及相关文章等内容

374

2023.07.04

js四舍五入
js四舍五入

js四舍五入的方法:1、tofixed方法,可把 Number 四舍五入为指定小数位数的数字;2、round() 方法,可把一个数字舍入为最接近的整数。php中文网为大家带来了js四舍五入的相关知识、以及相关文章等内容

731

2023.07.04

js删除节点的方法
js删除节点的方法

js删除节点的方法有:1、removeChild()方法,用于从父节点中移除指定的子节点,它需要两个参数,第一个参数是要删除的子节点,第二个参数是父节点;2、parentNode.removeChild()方法,可以直接通过父节点调用来删除子节点;3、remove()方法,可以直接删除节点,而无需指定父节点;4、innerHTML属性,用于删除节点的内容。

477

2023.09.01

JavaScript转义字符
JavaScript转义字符

JavaScript中的转义字符是反斜杠和引号,可以在字符串中表示特殊字符或改变字符的含义。本专题为大家提供转义字符相关的文章、下载、课程内容,供大家免费下载体验。

394

2023.09.04

js生成随机数的方法
js生成随机数的方法

js生成随机数的方法有:1、使用random函数生成0-1之间的随机数;2、使用random函数和特定范围来生成随机整数;3、使用random函数和round函数生成0-99之间的随机整数;4、使用random函数和其他函数生成更复杂的随机数;5、使用random函数和其他函数生成范围内的随机小数;6、使用random函数和其他函数生成范围内的随机整数或小数。

990

2023.09.04

如何启用JavaScript
如何启用JavaScript

JavaScript启用方法有内联脚本、内部脚本、外部脚本和异步加载。详细介绍:1、内联脚本是将JavaScript代码直接嵌入到HTML标签中;2、内部脚本是将JavaScript代码放置在HTML文件的`<script>`标签中;3、外部脚本是将JavaScript代码放置在一个独立的文件;4、外部脚本是将JavaScript代码放置在一个独立的文件。

656

2023.09.12

Js中Symbol类详解
Js中Symbol类详解

javascript中的Symbol数据类型是一种基本数据类型,用于表示独一无二的值。Symbol的特点:1、独一无二,每个Symbol值都是唯一的,不会与其他任何值相等;2、不可变性,Symbol值一旦创建,就不能修改或者重新赋值;3、隐藏性,Symbol值不会被隐式转换为其他类型;4、无法枚举,Symbol值作为对象的属性名时,默认是不可枚举的。

551

2023.09.20

Golang gRPC 服务开发与Protobuf实战
Golang gRPC 服务开发与Protobuf实战

本专题系统讲解 Golang 在 gRPC 服务开发中的完整实践,涵盖 Protobuf 定义与代码生成、gRPC 服务端与客户端实现、流式 RPC(Unary/Server/Client/Bidirectional)、错误处理、拦截器、中间件以及与 HTTP/REST 的对接方案。通过实际案例,帮助学习者掌握 使用 Go 构建高性能、强类型、可扩展的 RPC 服务体系,适用于微服务与内部系统通信场景。

6

2026.01.15

热门下载

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

精品课程

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

共14课时 | 0.8万人学习

Bootstrap 5教程
Bootstrap 5教程

共46课时 | 2.9万人学习

CSS教程
CSS教程

共754课时 | 19万人学习

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

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