web

Next.js × microCMSで目次をつくる

公開日:2022年1月30日
最終更新日:2022年1月30日
目次
  • ライブラリ追加
  • 目次データを作る
  • 目次コンポーネントを作る
  • 参考サイト

microCMSで書いた記事のHeadingタグから目次を生成する方法です。

ライブラリ追加

HTMLをパースする jsdom を追加します。

yarn add jsdom @types/jsdom


目次データを作る

記事を生成する getStaticProps で以下のように書きます。
必要な部分だけ書き出しています。

import { JSDOM } from 'jsdom'

type Toc = {
  text: string | null
  id: string
  name: string
}

export const getStaticProps: GetStaticProps<StaticProps> = async (context) => {
  const { params, previewData } = context
  if (!params?.category || !params?.id) {
    throw new Error('Error: ID not found')
  }

  try {
    const id = toStringId(params.id)
    const data = await client.get({
      endpoint: 'blog',
      contentId: id,
    })


    const dom = new JSDOM(data.content)
    const toc: Toc[] = []
    dom.window.document
      .querySelectorAll('h1, h2, h3, h4, h5, h6')
      .forEach((heading) => {
        toc.push({
          id: heading.id,
          name: heading.tagName,
          text: heading.textContent,
        })
      })

    const category = await client.get({
      endpoint: 'blog-category',
    })

    return {
      props: {
        blog: data,
        toc: toc,
        category: category.contents,
        currentCategory: toStringId(params.category),
      },
    }
  } catch (e) {
    return { notFound: true }
  }
}


目次コンポーネントを作る

目次データで配列が作られたのであとはそれを表示させればOKです。
本当は1~6のレベルで入れ子にできたらいいんですけど、面倒なので階層なしのリストにしました。
以下は例です。

export const Toc = ({ className, items }: Props) => {
  return (
    <Details className={className} open>
      <Summary>目次</Summary>
      <List className={className}>
        {items.map((item, index) => (
          <Item key={`${item.id}-${index}`} name={item.name}>
            <Link href={`#${item.id}`}>{item.text}</Link>
          </Item>
        ))}
      </List>
    </Details>
  )
}


開閉できるようにSummary要素を使ってみました。
今回はページ内スクロールは実装していませんが、目次クリックでスクロールして欲しい場合は、react-scroll というライブラリを使うといいみたいです。
https://www.npmjs.com/package/react-scroll

参考サイト

以下の記事にあるGitHubリポジトリを参考にしました。
microCMSブログのNext.js版を作成した

About the author

大阪でフロントエンドエンジニアをしています。写真を撮るのが趣味です。よかったら500pxに載せてる写真も見てください。
web上に公開しているので、正確さに可能な限り努力してますが、個人の備忘録程度に書いてるので、ご自身の判断で参考程度に読んでください。
間違いやご意見があれば、コンタクトやSNSに気軽にご連絡ください。

Read next

Category

  • web
  • 雑記