MENU
  • HOME
  • Arkhe
  • 知識ブログ一覧
日々の知識をOutputしよう
OutPut
  • HOME
  • Arkhe
  • 知識ブログ一覧
  • HOME
  • Arkhe
  • 知識ブログ一覧
OutPut
  • HOME
  • Arkhe
  • 知識ブログ一覧
  1. ホーム
  2. 知識ブログ
  3. JavaScript
  4. 【JavaScript】目次をセクションの見出しから自動生成する機能を作成してみた

【JavaScript】目次をセクションの見出しから自動生成する機能を作成してみた

2024 4/18
JavaScript
2024年4月18日

今回は、目次をセクションの見出しから自動生成する機能を素のJSを使って、実装してみます。

目次

目次を作成するにあたっての仕様

以下の仕様にしています。

目次を作成するにあたっての仕様
  • 空のulを用意して、その中に、liとaタグを新たに作成して、ulの子要素として、挿入する。
  • h2(.sec–ttl)見出しの目次を作成する。
  • 目次をサイドに固定させる。(CSS)
  • スクロールは滑らかにする。(CSS)

この仕様に沿って、実際に目次を作成してみましょう。

目次の完成形

目次の完成形がこちらになります。

See the Pen サイドバー固定の目次を自動生成する by レメ (@grozxntv-the-sasster) on CodePen.

目次を実際に作ってみよう

基本的な流れは以下の通りです。

  • ulタグの直下にliタグとaタグを生成する。
  • アンカーリンクをh2タグのid属性に付与し、リンクを追加
  • セクションタイトルごとに目次アイテムを作成し、目次リストアイテムを一度にDOMに追加

HTMLは以下で準備します。

  <div class="container">
    <section class="sec">
      <h2 class="sec--ttl">タイトル1</h2>
      <p class="sec--txt">ここにテキストが入ります。</p>
    </section>
    <section class="sec">
      <h2 class="sec--ttl">タイトル2</h2>
      <p class="sec--txt">ここにテキストが入ります。</p>
    </section>
    <section class="sec">
      <h2 class="sec--ttl">タイトル3</h2>
      <p class="sec--txt">ここにテキストが入ります。</p>
    </section>
    <section class="sec">
      <h2 class="sec--ttl">タイトル4</h2>
      <p class="sec--txt">ここにテキストが入ります。</p>
    </section>
    <section class="sec">
      <h2 class="sec--ttl">タイトル5</h2>
      <p class="sec--txt">ここにテキストが入ります。</p>
    </section>
  </div>
  <div class="toc" id="toc">
    <div class="toc--inner">
      <ul class="toc--list"></ul>
    </div>
    <!-- /.toc--inner -->
  </div>

CSSは、今回適当ですが、滑らかにスクロールさせるために、scroll-behavior: smooth; を適用しています。

html {
  scroll-behavior: smooth;
}

body {
  margin: 0;
  box-sizing: border-box;
  height: 3000px;
}
.container {
  position: relative;
}
.sec--ttl {
  font-size: 32px;
}
.sec {
  height: 400px;
  background-color: rgb(205, 205, 205);
  border: 1px solid black;
}
.toc {
  position: fixed;
  top: 100px;
  right: 0;
  background-color: skyblue;
  padding: 16px;
}
.toc--list_item {
  padding: 1em;
}

ulタグの直下にliタグとaタグを生成する

まずは、セレクタを変数に格納しましょう。

.secと.sec--ttlのクラスを持つ要素は今回、複数あるので、querySelectorAllで取得しましょう。

// セレクタを変数に格納する
const container = document.querySelector('.container');
const sections = document.querySelectorAll('.sec');
const sectionTitles = document.querySelectorAll('.sec--ttl');
const tocList = document.querySelector('.toc--list');

ulタグの直下にliタグとaタグを生成するためには、createElementメソッドを使いましょう。

作成したら、appendChildメソッドでulタグの子ノードリストの末尾にノードを追加します。

const tocListItem = document.createElement('li');
const tocListLink = document.createElement('a');
tocListItem.appendChild(tocListLink);

アンカーリンクをh2タグのid属性に付与し、リンクを追加

setAttributeメソッドを使って、id属性にsec–ttl1,sec–ttl2,sec–ttl3と付与していく。

function createTOCItem(title, index) {
  title.setAttribute('id', `sec--ttl${index + 1}`);
  const titleId = title.getAttribute('id');
  tocListItem.classList.add(`toc--list_item${index + 1}`, 'toc--list_item');
  tocListItem.appendChild(tocListLink);
  tocListLink.setAttribute('href', `#${titleId}`);
}

上記の手順を組み合わせて、目次リストアイテムを作成する関数が完成。

// 目次リストアイテムを作成する関数を定義
function createTOCItem(title, index) {
  title.setAttribute('id', `sec--ttl${index + 1}`);
  const titleId = title.getAttribute('id');
  const titleText = title.textContent;

  // 目次リストアイテムを作成し、リンクを追加
  const tocListItem = document.createElement('li');
  const tocListLink = document.createElement('a');
  tocListLink.textContent = titleText;
  tocListItem.classList.add(`toc--list_item${index + 1}`, 'toc--list_item');
  tocListItem.appendChild(tocListLink);
  tocListLink.setAttribute('href', `#${titleId}`);

  return tocListItem;
}

セクションタイトルごとに目次アイテムを作成し、目次リストアイテムを一度にDOMに追加

最後にmapメソッドを使いますが、Arrayインスタンスのメソッドで、与えられた関数を配列のすべての要素に対して呼び出し、その結果からなる新しい配列を生成するので、Array.fromとしている。

目次リストアイテムを一度にDOMに追加することで、余分なDOM操作をせず、パフォーマンスを上げることができます。

// セクションタイトルごとに目次アイテムを作成
const tocItems = Array.from(sectionTitles).map((title, index) => createTOCItem(title, index));

// 目次リストアイテムを一度にDOMに追加
tocItems.forEach(item => tocList.appendChild(item));

全てのコード

// セレクタを変数に格納する
const container = document.querySelector('.container');
const sections = document.querySelectorAll('.sec');
const sectionTitles = document.querySelectorAll('.sec--ttl');
const tocList = document.querySelector('.toc--list');

// 目次リストアイテムを作成する関数を定義
function createTOCItem(title, index) {
  title.setAttribute('id', `sec--ttl${index + 1}`);
  const titleId = title.getAttribute('id');
  const titleText = title.textContent;

  // 目次リストアイテムを作成し、リンクを追加
  const tocListItem = document.createElement('li');
  const tocListLink = document.createElement('a');
  tocListLink.textContent = titleText;
  tocListItem.classList.add(`toc--list_item${index + 1}`, 'toc--list_item');
  tocListItem.appendChild(tocListLink);
  tocListLink.setAttribute('href', `#${titleId}`);

  return tocListItem;
}

// セクションタイトルごとに目次アイテムを作成
const tocItems = Array.from(sectionTitles).map((title, index) => createTOCItem(title, index));

// 目次リストアイテムを一度にDOMに追加
tocItems.forEach(item => tocList.appendChild(item));
JavaScript
よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!
  • JavaScriptのDOM操作について詳しくまとめる【メモ】

この記事を書いた人

remeのアバター reme

ブログ「OutPut」の運営者。私自身がインプット→アウトプットの場として作成しました。また、それをあなたがインプット→アウトプットする機会になれれば嬉しいと思い、この名前にしました。
【シンプルでわかりやすい】を心がけて記事を書いています!

関連記事

  • CSSのcounter-incrementを使って簡単に自動で連番をつける方法
    2024年3月30日
  • CSSのgridを使って、アイコン付きのボタンを作ってみる【活用法】
    CSSのgridを使って、アイコン付きのボタンを作ってみる【活用法】
    2024年4月6日
  • JavaScriptのDOM操作について詳しくまとめる【メモ】
    2024年4月13日

コメント

コメントする コメントをキャンセル

カテゴリー
  • HOME
  • Arkhe
  • 知識ブログ一覧

© OutPut.

目次