JavaScriptを使い、目次をプラグイン無しで自動生成する方法

JavaScriptを使い、WordPress記事などの目次をプラグイン無しで実装したい。
目次に順番がわかるように番号を付与したい。
本記事ではこのような悩みを解決。
実装方法について解説します。
目次の実装
// 目次生成
document.addEventListener('DOMContentLoaded', () => {
var heads = document.querySelectorAll('h2, h3, h4, h5, h6');
var className = 'head'; //クラス
var numText = 0; //目次番号
// 目次番号 初期値
var num02 = 0;
var num03 = 0;
var num04 = 0;
var num05 = 0;
var num06 = 0;
// hタグの数だけループ
// 上位のhタグに上がると、下位のhタグ目次番号をリセット
if (heads && heads.length) {
var contents = '';
heads.forEach((head, i) => {
if (head.localName == 'h2') {
className = 'toc02';
num02++;
numText = num02;
num03 = 0;
} else if (head.localName == 'h3') {
className = 'toc03';
num03++;
numText = num02 + '.' + num03;
num04 = 0;
} else if (head.localName == 'h4') {
className = 'toc04';
num04++;
numText = num02 + '.' + num03 + '.' + num04;
num05 = 0;
} else if (head.localName == 'h5') {
className = 'toc05';
num05++;
numText = num02 + '.' + num03 + '.' + num04 + '.' + num05;
num06 = 0;
} else if (head.localName == 'h6') {
className = 'toc06';
num06++;
numText = num02 + '.' + num03 + '.' + num04 + '.' + num05 + '.' + num06;
}
// hタグにアンカーを付与
head.innerHTML += `<span id="head${i}"></span>`;
// 目次にhタグのタイトルリストを追加
contents += `<li class="${className}"><a href="#head${i}"><span>${numText}</span>${head.textContent}</a></li>`;
})
document.querySelector('#toc').innerHTML += `<ul>${contents}</ul>`;
}
});
目次を自動生成するJavaScriptコード例です。
予め、ID要素tocをdivタグで生成してください。
その中に目次が生成されます。
実装方法の詳細は以下の通りです。
DOMを読み込んでから実行する関数を定義
まず最初にaddEventListener(‘DOMContentLoaded’)を定義。DOMを読み込んでからJavaScriptが実行するようにします。
hタグを全て取得。目次番号の初期値を定義
querySelectorAllをつかって記事内に入ってるhタグ(本記事ではh2からh6まで)を全て取得します。
次に本記事では目次のリストに数値で順番を振りたいので、目次番号を変数として定義。
初期値で0を代入します。
forEachでhタグの数だけループ。目次リストを生成
forEachを使ってquerySelectorAllで取得したhタグの数だけアンカーリンクが入ったタイトルリストを目次内に生成します。
if文でhタグ毎に条件分岐。
同じhタグがループされる度にページ番号が加算。
上位のhタグになったら下位のページ番号がリセットされるようにします。
hタグにアンカーを設定
hタグにinnerHTMLを使ってアンカーを設定。
目次のタイトルをクリックしたら該当するhタグへページ内リンクされるようにします。
以上で目次の実装完了です。
目次をクリックしたらスムーススクロールさせる
// 目次生成
document.addEventListener('DOMContentLoaded', () => {
var heads = document.querySelectorAll('h2, h3, h4, h5, h6');
var className = 'head'; //クラス
var numText = 0; //目次番号
// 目次番号 初期値
var num02 = 0;
var num03 = 0;
var num04 = 0;
var num05 = 0;
var num06 = 0;
// hタグの数だけループ
// 上位のhタグに上がると、下位のhタグ目次番号をリセット
if (heads && heads.length) {
var contents = '';
heads.forEach((head, i) => {
if (head.localName == 'h2') {
className = 'toc02';
num02++;
numText = num02;
num03 = 0;
} else if (head.localName == 'h3') {
className = 'toc03';
num03++;
numText = num02 + '.' + num03;
num04 = 0;
} else if (head.localName == 'h4') {
className = 'toc04';
num04++;
numText = num02 + '.' + num03 + '.' + num04;
num05 = 0;
} else if (head.localName == 'h5') {
className = 'toc05';
num05++;
numText = num02 + '.' + num03 + '.' + num04 + '.' + num05;
num06 = 0;
} else if (head.localName == 'h6') {
className = 'toc06';
num06++;
numText = num02 + '.' + num03 + '.' + num04 + '.' + num05 + '.' + num06;
}
// hタグにアンカーを付与
head.innerHTML += `<span id="head${i}"></span>`;
contents += `<li class="${className}"><a href="#head${i}"><span>${numText}</span>${head.textContent}</a></li>`;
})
document.querySelector('#toc').innerHTML += `<ul>${contents}</ul>`;
}
// アンカー・スムーススクロール
const offset = 0; // 固定ヘッダーの場合、ヘッダーの高さを入れる
const links = document.querySelectorAll('a[href^="#"]'); //すべてのaタグ href属性に#が入ってるもの
console.log(links);
// DOM内のa[href^="#"]の数だけループ
links.forEach((link) => {
// a[href^="#"]をクリックしたら
link.addEventListener('click', (event) => {
event.preventDefault();
//href属性の中身を取得
let href = link.getAttribute('href').substr(1);
href = href == '#' ? 'html' : `[id="${href}"]`;
//href属性のIDを変数に格納
const target = document.querySelector(href);
//上記IDの位置を取得
const rect = target.getBoundingClientRect();
//現在のスクロール量を取得
const scrollTop = window.pageYOffset || document.documentElement.scrollTop;
//固定ヘッダーの高さを引く
const position = rect.top + scrollTop - offset;
//スムーススクロール
window.scrollTo({
top: position,
behavior: 'smooth'
});
});
});
});
スムーススクロールさせる場合のコード例です。
前章に追加でscrollToメソッドを定義。
アンカーリンクの場合にスムーススクロールさせるようにします。
スムーススクロールの実装方法について詳しくはこちらを参照ください。
https://kasumiblog.org/js-smooth-scroll/
任意の箇所へ目次を動的に移動
WordPressなど最初のhタグ上などに目次を移動したいなどありますよね?
目次を任意の箇所へ動的に移動したい場合はinsertBeforeなどを使うと便利です。
insertBeforeの使い方について詳しくはこちらを参照ください。
https://kasumiblog.org/javascript-dom-move/
まとめ
JavaScriptを使い、目次をプラグイン無しで自動生成する方法について紹介しました。
以上で解説を終わります。