見出しを抽出して目次を自動生成するjavascript

今回は珍しくWeb系のお話です。

最近、wordpressに頼らずに自作のwebページを作成しているのですが、その際にページの見出しタグ(h1,h2など)を自動的に収集してきて勝手に目次を作ってくれるものが作れないかなと思い、自作してみましたので共有します。

目指すもの

このように、そのページ内にある見出しの文字列を収集して箇条書きにします。

そしてその箇条書きにした文字列をページ内リンクにし、クリックするとその見出しの箇所まで移動してくれるような目次を作成していきます。

筆者が作成したこちらのサイトのような見出しを目指します。

サンプルページ

サンプルとして、このようなhtmlのページがあったとします。この見出し1、見出し2、見出し3を収集して目次にしてみたいと思います。

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title>このページのタイトル</title>
	</head>
	<body>
		<h3>見出し1</h3>
		<p>本文</p>
		<h3>見出し2</h3>
		<p>本文</p>
		<h3>見出し3</h3>
		<p>本文</p>
	</body>
</html>

目次を作成するための箱(div)を用意

まずは、<body>内の頭に目次を生成するための箱を用意します。

<h3>目次</h3>
<div id="toc"></div>

idは何でも良いですが、ここではtoc(Table of Contentsの略)としておきます。

お好みですが、この目次自体にも見出しをつけておきます。

見出しを自動収集するjavascriptを書く

document.addEventListener('DOMContentLoaded', function () {
	var target_toc_id = 'toc';
	var target_headline = 'h3';
	var toc_contents = document.getElementById( target_toc_id );
	var matches = document.querySelectorAll( target_headline );
	var ul = document.createElement('ul');
	matches.forEach( function (value, i) {
		if ( value.id === '' ) {   // if tag has no id, add id
			value.id = i;
		}
		var li = document.createElement('li');
		var a = document.createElement('a');
		a.innerHTML = value.innerHTML;
		a.href = '#' + value.id;
		li.appendChild(a);
		ul.appendChild(li);
	});
	toc_contents.appendChild(ul);
});

このようなjsを作成します。わからない方はコピペで大丈夫です。

ここではとりあえず、toc_auto_generator.jsという名前で保存しておきました。

作成したjsを、目次を生成したいページのhead内で呼び出す

これを対象ページの<head>~</head>の中で読み込みます。

<script type="text/javascript" src="./auto_toc_generator.js" charset="utf-8"></script>

src=””の部分はどこにこのjavascriptを置くかによって変わりますので各自読み替えてください。

webページを自作している方でしたら、コードを読んだだけで何をしているかは大体わかると思いますので、多くは語りませんが、少し補足しておきます。

document.addEventListener(‘DOMContentLoaded’, function () {
目次の自動生成はDOMContentLoadedのタイミングで行われます。
これは、最初のHTMLドキュメントの読み込みと解析が完了した時に、スタイルシートや画像、サブフレームの読み込みが終わるのを待たずに発火します。

var target_toc_id = ‘toc’;
先ほど作成した目次を格納するdivタグのidをここで指定します。

var target_headline = ‘h3’;
収集するタグの種類を指定します。
ここではh3となっているが、h2やh4といったタグを使用している人は書き換えが必要です。

if ( value.id === ” ) {
目次はもちろんaタグによるページ内リンクとなります。
ページ内リンクはidを用いて行います。もし、その見出しにidがついていなかった場合には、for文のindex iを見出しのidとして設定しています。

以上、見出しを自動生成するjavascriptについてでした。