用details和summary可实现无JS的静态本地文件树,语义正确、无障碍友好;需确保summary为details首个子元素,嵌套层级清晰,避免div+class模拟导致键盘与ARIA支持缺失。

用 details 和 summary 实现最简本地文件树
不需要 JavaScript,纯 HTML 就能做出可折叠的本地文件结构——前提是你的“本地文件树”是静态生成的(比如文档站点、离线手册)。details 元素原生支持展开/收起,语义正确、无障碍友好、无 JS 依赖。
常见错误是试图用 div + class 模拟折叠,结果要写 JS 控制显隐、监听点击、管理 ARIA 属性,反而引入 focus 管理和键盘支持(Enter/Space)的坑。
实操建议:
-
details默认收起,加open属性让它默认展开 -
summary必须是details的第一个子元素,否则不生效 - 嵌套时,每个子目录独立用一组
details/summary,不要试图复用同一个元素 - 图标(▶/▼)建议用 CSS
::marker或伪元素控制,避免写死在文本里影响可访问性
<details>
<summary>src/</summary>
<details>
<summary>components/</summary>
<p><code>Button.jsx</code></p><p><span>立即学习</span>“<a href="https://pan.quark.cn/s/cb6835dc7db1" style="text-decoration: underline !important; color: blue; font-weight: bolder;" rel="nofollow" target="_blank">前端免费学习笔记(深入)</a>”;</p>
<p><code>Modal.css</code></p>
</details>
<p><code>index.js</code></p>
</details>
为什么不用 localStorage 记住展开状态
想让浏览器记住用户上次展开哪些目录?details 本身不持久,但加几行 JS 就能补全。重点不是“能不能”,而是“值不值得”——多数离线文档场景下,用户刷新页面后重新展开一两次,并不构成体验瓶颈。
把任意文章或文档内容转换成精美的全屏翻页 HTML 演示文件(幻灯片风格)。当用户发来一篇文章、文档链接、Markdown 内容、或粘贴的文本,并且希望生成演示用的 HTML 时触发。支持任意内容来源:iWiki 链接、KM 链接、本地文件路径、直接粘贴的文本。生成的 HTML 文件保存到本地工作区,并通过企微直接发送给用户。触发词示例:帮我把这篇文章做成PPT、转成演示文档、生成HTML幻灯片、做个演示、转成可以演示的格式、article to deck、make a slide。
如果真要持久化,注意这些实际问题:
- 不要监听
toggle事件后立刻存localStorage,它会在每次展开/收起都触发,高频写入可能卡顿 - 用
details.open读取当前状态,而不是靠 class 名判断 - 键名建议带路径哈希(如
tree-src-components),避免多个同名目录冲突 - 服务端渲染(SSR)页面要注意:JS 执行前 DOM 已渲染,默认收起,但 localStorage 值还没读取,会出现“闪动”
遇到 TypeError: detailsEl.toggleAttribute is not a function 怎么办
这是老版本 Safari(iOS 14.5 之前)或 IE 的典型报错——它们不支持 toggleAttribute。但你根本不需要它:操作 details 的展开状态,直接读写 open 属性即可。
错误写法:el.toggleAttribute('open')
正确写法(兼容所有支持 details 的浏览器):
const el = document.querySelector('details');
el.open = !el.open; // 直接赋值布尔值
其他兼容要点:
- 不要用
el.setAttribute('open', ''),这会让open变成字符串而非布尔值,后续!el.open判断失效 - 检查浏览器支持可用
'open' in document.createElement('details') - 服务端预渲染时,若需默认展开某节点,直接在 HTML 中写
<details open></details>,比 JS 注入更可靠
生成文件树时路径层级容易错乱
手动写嵌套 details 很快就晕——哪个 对应哪层?真实项目中,应该用脚本(如 Node.js 的 fs.readdirSync)递归遍历目录,生成 HTML 片段。
关键逻辑不是“怎么遍历”,而是“怎么保持缩进语义”:
- 每层递归传一个
depth参数,用于生成唯一 ID 或 data 属性,方便后续 JS 定位 - 避免用
<ul><li></ul>套details,因为details不是列表项,语义混乱且影响屏幕阅读器层级识别 - 文件名含特殊字符(如
&、)必须用 <code>textContent赋值或escape()处理,否则破坏 HTML 结构 - 大目录(如 >200 个子项)建议加
loading提示或分页,一次性渲染太多details会明显卡顿
复杂点不在技术实现,而在于:你是否真的需要客户端实时读取本地磁盘?如果目标是“展示结构”,静态生成足够;如果目标是“访问真实文件”,那已超出 HTML 能力范围,必须走 Electron、Tauri 或 Web API(如 showDirectoryPicker),而且用户得主动授权。


















