iT邦幫忙

2022 iThome 鐵人賽

DAY 20
0
Modern Web

從零開始打造炫砲個人部落格,使用 Next.js、ContentLayer、i18next 等現代技術系列 第 20

為內文小標題加入 anchor 錨點連結 - Modern Next.js Blog 系列 #20

  • 分享至 

  • xImage
  •  

TL;DR

這是「Modern Blog 30 天」系列第 20 篇文章,上一篇我們做完 RSS Feed 生成,完成所有部落格功能了。後續讓我們繼續加入更多炫砲細節。這篇先來為內文 heading 加入 anchor 連結!

結果截圖如下:

title anchor

這篇修改的程式碼如下:

https://github.com/Kamigami55/nextjs-tailwind-contentlayer-blog-starter/compare/day19-rss-feed...day20-custom-heading-anchor

我的個人網站裡也有此系列的好讀版,程式碼更易讀、也支援深色模式和側邊目錄,歡迎前往閱讀!


為內文小標題加入 anchor 錨點連結

使用 rehype-slug 套件在內文小標題補上 id 屬性

首先要讓每個內文小標題最後顯示的 HTML 都有 id 屬性,我們使用 rehype-slug 幫我們完成這件事。

它能在 Contentlayer 將 Markdown 內容轉成 HTML 時,將小標題補上 id

像是能把下列 HTML:

<h1 id=some-id>Lorem ipsum</h1>
<h2>Dolor sit amet ?</h2>
<h3>consectetur & adipisicing</h3>
<h4>elit</h4>
<h5>elit</h5>

補上 id 轉換成這樣:

<h1 id="some-id">Lorem ipsum</h1>
<h2 id="dolor-sit-amet-">Dolor sit amet ?</h2>
<h3 id="consectetur--adipisicing">consectetur & adipisicing</h3>
<h4 id="elit">elit</h4>
<h5 id="elit-1">elit</h5>

(範例取自 rehype-slug README.md

安裝 rehype-slug

pnpm add rehype-slug

修改 contentlayer.config.ts,將 rehype-slug 加入 rehypePlugins 列表:

// ...
import rehypeSlug from 'rehype-slug';

// ...

export default makeSource({
  // ...
  mdx: {
    rehypePlugins: [
      // 加入 rehypeSlug
      rehypeSlug, // For generating slugs for headings
      rehypeCodeTitles, // For adding titles to code blocks
      [rehypePrism, { ignoreMissing: true }], // For code syntax highlighting
    ],
  },
});

使用 CustomHeading 元件顯示 anchor 按鈕

接著讓每個小標題在 hover 時,顯示 anchor 按鈕。

這裡使用跟 Day 16 程式碼區塊樣式優化:複製按鈕 - Modern Blog 30 系列 #16 一樣的手法,用客製化 MDX 元件的方法實作。

當初實作複製按鈕時,我們實作了 <CustomPre/>,這次我們來實作 <CustomHeading/>

新增 src/components/CustomHeading.tsx

type CustomHeadingProps = React.ComponentPropsWithRef<
  'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6'
> & { Component: 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6' };

function CustomHeading({
  Component,
  id,
  children,
  ...otherProps
}: CustomHeadingProps) {
  return (
    <Component
      id={id}
      className="group scroll-mt-24 whitespace-pre-wrap"
      {...otherProps}
    >
      <span className="mr-3">{children}</span>
      <a
        href={id && `#${id}`}
        className="inline-flex h-6 w-6 items-center justify-center rounded-md text-lg text-slate-400 no-underline opacity-0 shadow-sm ring-1 ring-slate-900/5 transition-all hover:bg-slate-100 hover:text-slate-700 hover:shadow hover:ring-slate-900/10 group-hover:opacity-100 dark:text-slate-400 dark:ring-slate-400/20 dark:hover:text-slate-700"
        aria-label="Anchor"
      >
        #
      </a>
    </Component>
  );
}

export const CustomH1 = (props: React.ComponentPropsWithRef<'h1'>) => (
  <CustomHeading Component="h1" {...props} />
);
export const CustomH2 = (props: React.ComponentPropsWithRef<'h2'>) => (
  <CustomHeading Component="h2" {...props} />
);
export const CustomH3 = (props: React.ComponentPropsWithRef<'h3'>) => (
  <CustomHeading Component="h3" {...props} />
);
export const CustomH4 = (props: React.ComponentPropsWithRef<'h4'>) => (
  <CustomHeading Component="h4" {...props} />
);
export const CustomH5 = (props: React.ComponentPropsWithRef<'h5'>) => (
  <CustomHeading Component="h5" {...props} />
);
export const CustomH6 = (props: React.ComponentPropsWithRef<'h6'>) => (
  <CustomHeading Component="h6" {...props} />
);

修改 src/lib/mdxComponents.ts,加入 H1 到 H6 的客製化元件:

import {
  CustomH1,
  CustomH2,
  CustomH3,
  CustomH4,
  CustomH5,
  CustomH6,
} from '@/components/CustomHeading';
import CustomPre from '@/components/CustomPre';

// Custom components/renderers to pass to MDX.
const mdxComponents = {
  h1: CustomH1,
  h2: CustomH2,
  h3: CustomH3,
  h4: CustomH4,
  h5: CustomH5,
  h6: CustomH6,
  pre: CustomPre,
};

export default mdxComponents;

這樣就完成了!

成果

完成了!使用 pnpm dev,進到任何一篇內文有小標題的文章內,hover 小標題,就會看到旁邊多出井字號 anchor 按鈕,按下去畫面就會滾動到指定小標題,網址列也會隨之改變。

把這個網址貼給別人,別人進來看時,就會直接看到你希望他看的段落了。

結果截圖如下:

title anchor

這篇修改的程式碼如下:

https://github.com/Kamigami55/nextjs-tailwind-contentlayer-blog-starter/compare/day19-rss-feed...day20-custom-heading-anchor

References

下一篇

恭喜你在內文小標題加入 anchor 錨點,讓內文更實用了!

下一篇我們接著來修改內文 CustomLink,針對內部連結使用 Next.js 提供的 <Link/> 加速頁面切換,針對外部連結則加入 icon 提示使用者這是外部連結!


上一篇
使用 feed 生成 RSS Feed - Modern Next.js Blog 系列 #19
下一篇
強化內文連結換頁速度、加入外部連結 icon - Modern Next.js Blog 系列 #21
系列文
從零開始打造炫砲個人部落格,使用 Next.js、ContentLayer、i18next 等現代技術30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言