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版を作成した
Read next
- 2022年1月30日Next.js × microCMSでシンタックスハイライトをつける
- 2022年1月30日Next.js × microCMSでリッチエディタで書いた記事の画像にloading属性を付ける
- 2022年1月23日Next.js × algoliaで検索機能を実装する
- 2021年11月20日Next.js × microCMSでカテゴリ一覧ページを作る