在鸽了一段时间之后,终于又打算重新拾起这个Astro博客项目。接下来我计划将以往的笔记和博文迁移过来。在之前的Hexo项目中我使用的是hexo-markmap插件在博客中插入思维导图,现在需要在Astro中实现类似的功能。决定用markmap-render配合Astro的[slug],最后用<iframe>标签实现。 实现 安装依赖 yarn add markmap-common markmap-lib markmap-render 思维导图content src/content/markmaps/markmap-example.md1---2title: markmap示例3---4 5## Links6 7- [Website](https://markmap.js.org/)8- [GitHub](https://github.com/gera2ld/markmap)9 10## Related Projects11 12- [coc-markmap](https://github.com/gera2ld/coc-markmap) for Neovim13- [markmap-vscode](https://marketplace.visualstudio.com/items?itemName=gera2ld.markmap-vscode) for VSCode14- [eaf-markmap](https://github.com/emacs-eaf/eaf-markmap) for Emacs15 16## Features17 18Note that if blocks and lists appear at the same level, the lists will be ignored.19 20### Lists21 22- **strong** ~~del~~ *italic* ==highlight==23- \`inline code\`24- [x] checkbox25- Katex: $x = {-b \pm \sqrt{b^2-4ac} \over 2a}$ <!-- markmap: fold -->26 - [More Katex Examples](#?d=gist:af76a4c245b302206b16aec503dbe07b:katex.md)27- Now we can wrap very very very very long text based on \`maxWidth\` option28 29### Blocks30 31```js32 console.log('hello, JavaScript')33```34 35| Products | Price |36|-|-|37| Apple | 4 |38| Banana | 2 |39 40![](/icons/markmap.png) src/content/config.ts1const markmaps = defineCollection({2 schema: z.object({3 title: z.string().optional(),4 }),5});6export const collections = { markmaps }; slug绑定思维导图 src/pages/markmaps/[markmapName].astro1---2import { type CollectionEntry ,getCollection } from 'astro:content';3import { Transformer } from 'markmap-lib';4import { fillTemplate } from 'markmap-render';5//slug绑定思维导图6export async function getStaticPaths() {7 const markmaps = await getCollection('markmaps')8 return markmaps.map((markmap) => ({9 params: { markmapName: markmap.slug },10 props: markmap,11 }));12}13//astro props14type Props = CollectionEntry<'markmaps'>15const {markmapName} = Astro.params;16const markmap = Astro.props;17//生成渲染后的html18const transformer = new Transformer();19const { root, features } = transformer.transform(markmap.body);20const assets = transformer.getUsedAssets(features);21const html = fillTemplate(root, assets);22---23<html set:html={html}></html>24 25<title>{markmap.data.title || markmapName.toLocaleUpperCase()}</title>26<script is:inline>27 //所有a标签改为新标签页打开,防止iframe嵌套时跳转异常28 window.addEventListener("DOMContentLoaded",()=>document.querySelectorAll("a").forEach(a=>a.target="_blank"))29</script> iframe实现Component src/components/Markmap.astro1---2interface Props {3 name: string;4 height: string;5}6const { name, height } = Astro.props7const title = (await getCollection('markmaps')).find(m=>m.slug==name)?.data?.title8---9 10<div class="markmap-block">11 <div class="markmap-block-toolbar">12 <div class="markmap-name">{ title||name }</div>13 <svg class="link-btn btn" onclick=`window.open('/markmaps/${name}/')` xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><title>在新标签页打开</title><path d="M14,3V5H17.59L7.76,14.83L9.17,16.24L19,6.41V10H21V3M19,19H5V5H12V3H5C3.89,3 3,3.9 3,5V19A2,2 0 0,0 5,21H19A2,2 0 0,0 21,19V12H19V19Z" /></svg>14 <svg class="expend-btn btn" onclick="this.parentNode.nextElementSibling.hidden = !this.parentNode.nextElementSibling.hidden" viewBox="0 0 24 24"><path d="M7.41,8.58L12,13.17L16.59,8.58L18,10L12,16L6,10L7.41,8.58Z"></path></svg>15 </div>16 <iframe class="markmap" style={`height:${height||'unset'}`} src={`/markmaps/${name}/`} loading="lazy"></iframe>17</div>18 19<style lang="scss" is:global>20.markmap-block{display:flex;flex-direction:column;border-radius:0.5em;overflow:hidden;border:1.5px solid #d9d9d9;box-shadow:0.1rem 0.1rem 0.2rem #00000028;.markmap{width:100%;border:0;outline:0;}.markmap-block-toolbar{display:flex;height:2.15em;background:#eef3f4;font-size:16px;align-items:center;user-select:none;padding-left:1em;svg{fill:var(--font-color);}.markmap-name{width:100%;text-transform:uppercase;font-weight:bold;}.link-btn{height:1.2em;width:2em;display:none;}.expend-btn{height:1.4em;width:2em;padding-right:0.6em;}}&:hover{.markmap-block-toolbar .link-btn{display:unset;}}}21</style> 在mdx中使用 src/content/posts/mypost.mdx1import Markmap from '@/components/Blog/Markmap.astro';2 3<Markmap name="markmap-example" height="500px"/> 效果 markmap示例 在新标签页打开