HTML中图表编号自动化

网页中图表的图 n 这种编号进行自动编号的技术,这里采用 JS脚本实现。

图表应该如何编号

  1. 正常期刊论文就是直接从1开始编号,也就是图1,图2这种

  2. 长篇论文/书籍中可能会按照章进行编号(因为图表可能很多),图3-1图3.1这两种方式都存在

    • 英文书籍中第3章第1个图主流采用 Figure 3.1这种方式, 3-1 的方式偶见于工程报告传统。
    • 中文的主流做法则是图3-1这种方式,3.1 也是合规写法,但是应该更推荐用 3-1 。估计是为了避免和章节混淆(因为 3.1 放在章节中是第3章第1节的意思)。所以使用 3-1 在防混淆这件事上其实设计得更好。

    其实这就是约定俗成而已,深挖一下应该是语言和语法传统的原因。英文里就是用 . 表示层级隶属关系,而-除了连字符,还有减号/范围的含义,如果不加前缀 Figure 就会产生误解。但是中文语境下的 - 只有连字符的含义,没有数值含义。

从1开始自动编号的做法

首先你的代码中本身应该是编号的地方改为占位符 @N ,图表加一个类别 “fig-auto” 或 “tbl-auto” (图表一定要有标题,标题中要有 @N,不然就会跳号了)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<figure class="fig-auto">
<img src="flowchart.png" alt="">
<figcaption>
图 @N GWAS分析标准流程<br>
Figure @N GWAS analysis workflow
</figcaption>
</figure>

<table class="tbl-auto">
<caption>
表 @N 所有性状显著位点和候选基因数目统计表<br>
Table @N Summary statistics of significant loci and candidate genes across all traits
</caption>
<thead></thead>
<tbody></tbody>
</table>

然后使用的 JS 脚本如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
<script>
(function () {
/* ---- 图 ---- */
document.querySelectorAll('figure.fig-auto').forEach((fig, i) => {
const n = i + 1;
const cap = fig.querySelector(':scope > figcaption');
if (!cap) return;
replaceTextInNode(cap, '@N', ' ' + n); // 把编号嵌进文本节点
// 第一行的 "图 " 前缀你已经手写在了 HTML 里,我们只替换 @N
});

/* ---- 表 ---- */
document.querySelectorAll('table.tbl-auto').forEach((tbl, i) => {
const n = i + 1;
const cap = tbl.querySelector(':scope > caption');
if (!cap) return;
replaceTextInNode(cap, '@N', ' ' + n);
});

/* 核心:只改 TEXT_NODE 的 textContent,不动 innerHTML,不杀事件监听器 */
function replaceTextInNode(root, placeholder, replacement) {
const walker = document.createTreeWalker(
root,
NodeFilter.SHOW_TEXT,
null,
false
);
const nodesToChange = [];
while (walker.nextNode()) {
if (walker.currentNode.nodeValue.includes(placeholder)) {
nodesToChange.push(walker.currentNode);
}
}
nodesToChange.forEach(node => {
node.nodeValue = node.nodeValue.replace(
new RegExp(escapeRegExp(placeholder), 'g'),
replacement
);
});
}

function escapeRegExp(string) {
return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
}
})();
</script>

这个脚本的做法是

  • 选取所有类名为 fig-auto<figure> 元素,遍历它们,i 是从 0 开始的下标,编号 n = i + 1(从 1 开始)。然后将 <figcaption> 内所有文本节点中的 @N 替换为 " " + n(即空格加编号)。
  • 表格同理
  • 替换文本的函数为 replaceTextInNode()
    • 遍历 root 下的所有文本节点NodeFilter.SHOW_TEXT),而不是直接用 innerHTMLtextContent 整体替换。
    • 这样做的好处是只修改纯文本内容,不破坏 HTML 结构、不重新解析 DOM,也不会移除已绑定的事件监听器(因为 innerHTML 会清空并重建元素,导致事件丢失)。
    • 收集所有包含占位符的文本节点(includes(placeholder)),然后统一替换。
    • 替换过程
      • 使用 new RegExp(escapeRegExp(placeholder), 'g') 进行全局替换。
      • escapeRegExp 用于转义占位符中的正则特殊字符(如 .*+ 等),确保按字面意义匹配。

修改

图表不用加类别 “fig-auto” 或 “tbl-auto” ,就默认对全部图表进行自动编号。正常应该就是这样,不存在哪个图表是人为要求不需要编号的。

HTML 的图为

1
2
3
4
5
6
7
<figure>
<img src="flowchart.png" alt="">
<figcaption>
图 @N GWAS分析标准流程<br>
Figure @N GWAS analysis workflow
</figcaption>
</figure>

HTML 中的表为

1
2
3
4
5
6
7
8
<table>
<caption>
表 @N 所有性状显著位点和候选基因数目统计表<br>
Table @N Summary statistics of significant loci and candidate genes across all traits
</caption>
<thead></thead>
<tbody></tbody>
</table>

JS 代码为

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
<script>
(function () {
/* ---------- 配置 ----------
* tokenFig / tokenTbl:和你 HTML 里的占位记号完全一致
* prefixZH / prefixEN 也可在这里统一改(如果你想中英文间距/格式更可控)
*/
const TOKEN_FIG = '@N';
const TOKEN_TBL = '@N';

/* 工具:在 root 子树的所有文本节点里,把 token 替换为 replacement */
function replaceTokenInTextNodes(root, token, makeReplacement) {
if (!root) return;
const walker = document.createTreeWalker(
root,
NodeFilter.SHOW_TEXT,
null,
false
);
// 先收集再改,避免在遍历中修改引起意外行为
const hits = [];
while (walker.nextNode()) {
const node = walker.currentNode;
if (node.data.includes(token)) hits.push(node);
}
for (const node of hits) {
// 注意:这里只做纯文本替换,不碰 innerHTML,不破坏子元素
node.data = node.data.split(token).join(makeReplacement);
}
}

/* ---- 1) 图编号 ----
* 只处理“带 figcaption 的 figure”,避免把页面里非报告的 figure 也卷进来
*/
document.querySelectorAll('figure').forEach((fig, i) => {
const cap = fig.querySelector(':scope > figcaption');
if (!cap) return; // 没标题就不算“报告图”
const n = i + 1;
// 如果你只想在编号位填数字(前缀留在 HTML 里),用:
replaceTokenInTextNodes(cap, TOKEN_FIG, n);
// 如果你宁愿把整个前缀也管起来(更严格),可以改成填整句:
// replaceTokenInTextNodes(cap, TOKEN_FIG, '图 ' + n);
// replaceTokenInTextNodes(cap, TOKEN_FIG_EN, 'Figure ' + n);
});

/* ---- 2) 表编号 ----
* <caption> 按规范必须是 <table> 的第一个子元素,我们直接取 caption
*/
document.querySelectorAll('table').forEach((tbl, i) => {
const cap = tbl.querySelector(':scope > caption');
if (!cap) return; // 没 caption 就不编
const n = i + 1;
replaceTokenInTextNodes(cap, TOKEN_TBL, n);
});
})();
</script>

好家伙,给我的代码更稳健了。

修改的地方

HTML 代码

  • 不用特定加类别。

JS 代码

  • 不加类:选择器就是 figure/ table,全文档生效
  • 不用 innerHTML:用 document.createTreeWalker(..., NodeFilter.SHOW_TEXT)只改 .data,不重建子树、不杀 <br>/<span>/图片引用
  • <caption>的位置符合规范<caption>必须是 <table>的第一子元素,所以我们用 table > caption定位是合法且可靠的
  • 如果存在无标题的图表,自动编号会跳过这个图/表(所以就不会存在跳号的情况)。
  • 版权声明: 本博客所有文章除特别声明外,著作权归作者所有。转载请注明出处!
  • Copyrights © 2019-2026 Vincere Zhou
  • 访问人数: | 浏览次数:

请我喝杯茶吧~

支付宝
微信