本文已过时,推荐使用 remark-markmap 插件方案
过时方案
在鸽了一段时间之后,终于又打算重新拾起这个Astro博客项目。接下来我计划将以往的笔记和博文迁移过来。在之前的Hexo项目中我使用的是hexo-markmap插件在博客中插入思维导图,现在需要在Astro中实现类似的功能。决定用markmap-render配合Astro的[slug]
,最后用<iframe>
标签实现。
实现
安装依赖
yarn add markmap-common markmap-lib markmap-render
思维导图content
---title: markmap示例---
## Links
- [Website](https://markmap.js.org/)- [GitHub](https://github.com/gera2ld/markmap)
## Related Projects
- [coc-markmap](https://github.com/gera2ld/coc-markmap) for Neovim- [markmap-vscode](https://marketplace.visualstudio.com/items?itemName=gera2ld.markmap-vscode) for VSCode- [eaf-markmap](https://github.com/emacs-eaf/eaf-markmap) for Emacs
## Features
Note that if blocks and lists appear at the same level, the lists will be ignored.
### Lists
- **strong** ~~del~~ *italic* ==highlight==- \`inline code\`- [x] checkbox- Katex: $x = {-b \pm \sqrt{b^2-4ac} \over 2a}$ <!-- markmap: fold --> - [More Katex Examples](#?d=gist:af76a4c245b302206b16aec503dbe07b:katex.md)- Now we can wrap very very very very long text based on \`maxWidth\` option
### Blocks
```js console.log('hello, JavaScript')```
| Products | Price ||-|-|| Apple | 4 || Banana | 2 |

const markmaps = defineCollection({ schema: z.object({ title: z.string().optional(), }),});export const collections = { markmaps };
slug绑定思维导图
---import { type CollectionEntry ,getCollection } from 'astro:content';import { Transformer } from 'markmap-lib';import { fillTemplate } from 'markmap-render';//slug绑定思维导图export async function getStaticPaths() { const markmaps = await getCollection('markmaps') return markmaps.map((markmap) => ({ params: { markmapName: markmap.slug }, props: markmap, }));}//astro propstype Props = CollectionEntry<'markmaps'>const {markmapName} = Astro.params;const markmap = Astro.props;//生成渲染后的htmlconst transformer = new Transformer();const { root, features } = transformer.transform(markmap.body);const assets = transformer.getUsedAssets(features);const html = fillTemplate(root, assets);---<html set:html={html}></html>
<title>{markmap.data.title || markmapName.toLocaleUpperCase()}</title><script is:inline> //所有a标签改为新标签页打开,防止iframe嵌套时跳转异常 window.addEventListener("DOMContentLoaded",()=>document.querySelectorAll("a").forEach(a=>a.target="_blank"))</script>
iframe实现Component
---interface Props { name: string; height: string;}const { name, height } = Astro.propsconst title = (await getCollection('markmaps')).find(m=>m.slug==name)?.data?.title---
<div class="markmap-block"> <div class="markmap-block-toolbar"> <div class="markmap-name">{ title||name }</div> <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> <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> </div> <iframe class="markmap" style={`height:${height||'unset'}`} src={`/markmaps/${name}/`} loading="lazy"></iframe></div>
<style lang="scss" is:global>.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;}}}</style>
在mdx中使用
import Markmap from '@/components/Blog/Markmap.astro';
<Markmap name="markmap-example" height="500px"/>
评论