效果如下
原理
扫描 .markdown 下的 h1~h4 标题,组装成 antd 的 Anchor
代码
需要用到 antd 的 Anchor 组件
import { Anchor } from 'antd';
const App = () => {
const [anchors, setAnchors] = useState([]);
const updateToc = () => {
setTimeout(() => {
const article = document.querySelector(".markdown-body");
if (null === article || article.hasAttribute('querySelectorAll')) return;
const hs = article.querySelectorAll('h1,h2,h3,h4');
const anchor = [];
hs.forEach((item, idx) => {
const h = item.nodeName.substring(0, 2).toLowerCase();
item.id = `Anchor-${h}-${idx}`;
anchor.push({id: `Anchor-${h}-${idx}`, text: item.textContent});
})
setAnchors(anchor)
}, 100);
}
return (
<>
<Anchor
offsetTop={1}
affix={false}
showInkInFixed={true}
>
{anchors.map((anchor, idx) => {
switch (anchor.id[8]) {
case "1": return <Anchor.Link key={idx} href={`#${anchor.id}`} title={<span style={{paddingLeft: 0}}>{anchor.text}</span>}/>
case "2": return <Anchor.Link key={idx} href={`#${anchor.id}`} title={<span style={{paddingLeft: 16}}>{anchor.text}</span>}/>
case "3": return <Anchor.Link key={idx} href={`#${anchor.id}`} title={<span style={{paddingLeft: 32}}>{anchor.text}</span>}/>
default: return <></>
}
})}
</Anchor>
</>
);
}