自動產生 HTML 文件的目錄 (table of content)
需求
有一 HTML 文件有以下的內容. 需要自動產生目錄(Table of Content)的超連結, 放置於 div#toc
上.
<body>
<div id="toc"></div>
<article>
<h1>header 1</h1>
<h2>header 1-1 </h2>
<h2>header 1-2 </h2>
<h1>header 2</h1>
<h2>header 2-1 </h2>
<h2>header 2-2 </h2>
</article>
</body>
實作 1 (by Hendrik [1])
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
56
57
58
59
60
61
62
63
64
65
66
67
68
/*
Parameter:
container - 含有 h1 ~ h6 標題的容器的 selector, 例如: 'article'.
output - 要放置輸出結果的容器的 selector, 例如, 'div#toc'.
Example:
TableOfContents('article', 'div#toc');
*/
function TableOfContents(container, output) {
// 目錄輸出的結果
var toc = "";
// 在第幾層的目錄
var level = 0;
// 含有 h1 ~ h6 標題的容器
var container = document.querySelector(container) || document.querySelector('#contents');
// 要放置輸出結果的容器
var output = output || '#toc';
container.innerHTML =
container.innerHTML.replace(
/<h([\d])>([^<]+)<\/h([\d])>/gi,
// Replacer
// str: 比對到的字串
// openLevel: regexp 中第 1 個括弧的內容, 表示起始標籤內的標題級數.
// titleText: regexp 中第 2 個括弧的內容, 標題標籤間的文字
// closeLevel: regexp 中第 3 個括弧的內容, 表示結束標籤內的標題級數.
function (str, openLevel, titleText, closeLevel) {
// 錯誤的 <h[\d]> 標籤, 起始和結束的標題級數不一致.
if (openLevel != closeLevel) {
return str;
}
if (openLevel > level) {
// Start a new level
toc += (new Array(openLevel - level + 1)).join('<ul>');
} else if (openLevel < level)
{
// Close a level
toc += (new Array(level - openLevel + 1)).join('</li></ul>');
} else {
// in the same level
toc += (new Array(level + 1)).join('</li>');
}
// Current Level. Default is 0
level = parseInt(openLevel);
// Make anchor string. Replace all space with underline char.
var anchor = titleText.replace(/ /g, "_");
// Accmulate the content using the local variable
toc += '<li><a href="#' + anchor + '">' + titleText +
'</a>';
// Return a reformated header with the anchor.
var item = '<h' + openLevel + '><a id="' + anchor + '">' +
'</a> ' + titleText + '</h' + closeLevel + '>';
return item;
}
);
// Append the final close tag for ul.
if (level) {
toc += (new Array(level + 1)).join('</ul>');
}
// append content to the output element.
document.querySelector(output).innerHTML += toc;
};
實作 2 (by matthewkastor [2])
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
function htmlTableOfContents(documentRef) {
var documentRef = documentRef || document;
var toc = documentRef.getElementById('toc');
// Convert to array
// the resultant arrary will contain the header elements in the order of the locations they appear.
// For example: h1 h2 h2 h1 h2 h2
var headings = [].slice.call(documentRef.body.querySelectorAll('h1, h2, h3, h4, h5, h6'));
// Generate a toc link for each header. Also, put an anchor before each header.
headings.forEach(function (heading, index) {
// Generate the anchor
var anchor = documentRef.createElement('a');
anchor.setAttribute('name', 'toc' + index);
anchor.setAttribute('id', 'toc' + index);
// put the anchor before the heading in the document.
heading.parentNode.insertBefore(anchor, heading);
// Make the TOC item link.
var link = documentRef.createElement('a');
link.setAttribute('href', '#toc' + index);
link.textContent = heading.textContent;
// put the line into a div
var div = documentRef.createElement('div');
div.setAttribute('class', heading.tagName.toLowerCase());
div.appendChild(link);
// append the div to toc element.
toc.appendChild(div);
});
}