纯html无法实现可交互思维笔记,因缺乏状态管理、拖拽、自动重排和折叠记忆能力;必须依赖javascript库(如markmap、jsmind)或手写svg+js方案。

纯 HTML 无法做出可交互的在线思维笔记页面——它没有状态管理、不支持节点拖拽、不能自动重排分支、也无法记忆折叠状态。所有“HTML 做思维笔记”的说法,实际都依赖 JavaScript 库或手动实现 SVG/Canvas 渲染逻辑。
为什么直接写 <div> + CSS 搞不定思维笔记
<p>看似能用 <code>flex 或 grid 排出树状结构,但只要加一个真实需求就崩:节点点击折叠时,子树要收起且父节点连线要重绘;拖拽一个节点,所有关联连线得实时跟随;缩放后文字不能糊、点击区域不能偏移。这些不是样式问题,是几何计算 + DOM 状态同步问题,document.querySelectorAll 和 getBoundingClientRect 都得用上,CSS 根本没能力接管。
- 跳级嵌套(比如
<h2></h2> 下直接 <h4></h4>)会导致大纲解析错乱,影响导出和读屏支持
- 用
display: none 控制节点显隐 → 折叠后连线位置丢失,再展开会错位
- 靠
max-height 动画做展开 → 高度固定则内容溢出,动态算又得触发重排,顺序一错动画就卡住或闪现
靠谱方案只有两个:用现成库 or 手写 SVG + JS
<h2></h2> 下直接 <h4></h4>)会导致大纲解析错乱,影响导出和读屏支持display: none 控制节点显隐 → 折叠后连线位置丢失,再展开会错位max-height 动画做展开 → 高度固定则内容溢出,动态算又得触发重排,顺序一错动画就卡住或闪现选库的话,markmap 最轻量,输入 Markdown 即可渲染带折叠的思维图,支持导出 SVG;jsMind 功能全,提供 API 控制节点增删、拖拽、主题切换,但体积大些。自己手写的话,必须用 <svg></svg> 而非 <div>,因为连线路径(<code><path d="M...L..."></path>)只能靠 JS 实时计算坐标生成,CSS transform 会把 getScreenCTM() 算出来的坐标搞偏。
-
markmap只需引入 script,调用markmap.bind('#map', markdownText),折叠靠data-folded属性控制 -
jsMind必须初始化jm = new jsMind(...),节点折叠用jm.fold_node('node_id'),状态不自动存 localStorage,得自己挂钩子 - 手写 SVG 方案里,每个节点得绑定
transform="translate(x,y)",连线<path></path>的d属性每次移动后重算,不能靠 CSS 动画过渡
折叠状态怎么记住?别硬塞 localStorage 键名
用户点开“前端基础”分支,刷新后还得开着——这得靠唯一 ID 绑定状态,而不是按 DOM 顺序存第 3 个节点是否展开。正确做法是给每个节点设 data-node-id="fe-core-001",存键为 node_fe-core-001_folded,值为 "false"(字符串,localStorage 只存字符串)。加载时遍历所有节点,读键、设类、再调用库的展开方法(如 jm.expand_node(id))。
- 新增节点后旧用户本地没对应 key → 默认折叠,安全
- 节点删了但 localStorage 还留着键 → 无害,下次读取时忽略即可
- 别用
JSON.stringify存整棵树状态 → 同步冲突风险高,单节点粒度最稳
真正卡住人的地方不在怎么画节点,而在怎么让“折叠”这个动作不破坏连线几何关系、不丢焦点、不和键盘导航(Tab 键)打架。一旦开始处理 aria-expanded、tabindex、focus() 和 SVG pointer-events 的配合,你就已经踩进交互逻辑深水区了。











