Table of Contents

2020-01-17 17:33

このサイトにもブログ機能を実装し、思うことあってブログ記事の書き方にMarkdown記法を使用することにしたので、有名なブログサービス等ではよくある、記事内に自動的に生成する「Table of Contents(目次)」機能を作ってみました。

目次機能を実装

当ブログ記事にあるような目次の開閉部分は省略します。あくまでもヘッディング要素から目次を作るのみにします。

HTML

index.html
<!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"> <title>Table of Contents Sample</title> </head> <body> <div id="blog-content"> <div id="toc"></div> <h2>H2のタイトル</h2> <p>H2の本文</p> <h3>H3のタイトル</h3> <p>H3の本文</p> <h2>H2のタイトル</h2> <p>H2の本文</p> <h3>H3のタイトル</h3> <p>H3の本文</p> <h3>H3のタイトル</h3> <p>H3の本文</p> <h4>H4のタイトル</h3> <p>H4の本文</p> </div> <script src="toc.js"></script> </body> </html>

JavaScript

今回もまた、ピュアなJavaScriptで実装してみます。

このブログの<H1>タグはページのタイトルで使っているので、目次要素として取得するのは<H2>から<H6>とします。

toc.js
var headers = Array.prototype.slice.call( document.querySelectorAll('h2,h3,h4,h5,h6')); var count = 1; var current = 1; var tag, level, close; headers.forEach( function( item, idx ) { tag = item.nodeName.toLowerCase(); level = Number( tag.substring(1)); close = false; item.setAttribute( 'id', 'anchor-'+ count ); if( current == level ){ close = true; } while( current < level ){ tag += '<ol>'; current++; } while( current > level ){ tag += '</ol>'; current--; } tag += '<li><a href="#anchor-'+ count +'">'+ item.textContent +'</a>'; if(close){ tag += '</li>'; } count++; }); while( current > 1 ){ tag += '</ol>'; current--; } document.getElementById('toc').innerHTML = tag;

変数tagに追加していく要素が文字列なのが面白くないので、改良版を作らないと。

スクロール機能を実装

折角なので、目次をクリックしたら目的の位置まで滑らかにスクロールする、も。

JavaScript

toc.js
・・・省略 Array.prototype.slice.call( document.querySelectorAll('#toc a'), 1 ).forEach( function( anchor, idx ) { anchor.addEventListener( 'click', function(e) { e.preventDefault(); window.scrollTo({ top: document.getElementById( anchor.getAttribute('href').substring(1)).getBoundingClientRect().top + window.pageYOffset, behavior: 'smooth' }); }); });