能用原生 HTML + JS 实现交互式文档系统:通过 fetch 加载、localStorage 缓存、IntersectionObserver 实现滚动锚点联动,iframe 沙箱运行代码示例,无需框架即可做到加载快、可离线、易部署、零构建。

能用原生 HTML + JS 实现的交互式文档系统,根本不需要框架——只要浏览器支持 fetch、localStorage、IntersectionObserver 和基础 DOM API,就能做到加载快、可离线、易部署、零构建。
怎么让文档页面支持实时代码示例运行
关键不是“渲染 Markdown”,而是让每个 <pre><code> 块自带可执行能力。不依赖 CodeMirror 或 Monaco,用原生 eval()(仅限本地 HTML 文件或可信环境)或更安全的沙箱方案:
- 给示例块加
data-exec="true"属性,并用textarea包裹原始代码,避免直接执行污染全局作用域 - 运行时创建新
<iframe sandbox="allow-scripts">,注入代码和最小运行时(如仅含console.log重定向到页面内<div class="output">) - 避免在主线程调用
eval();若必须,先用new Function(...)封装并绑定受限上下文 - 注意:Chrome 对本地文件(
file://)中fetch的限制,开发时用npx serve或 VS Code Live Server 启动本地服务
如何实现带锚点滚动与目录联动的单页文档
不用第三方滚动库,靠原生 scrollIntoView 和 IntersectionObserver 就够用,但要注意滚动偏移被固定 header 挡住的问题:
- 所有标题(
<h2>、<h3>)自动添加id,规则为id="section-xxx",全小写、去空格、去标点(用正则/[^a-z0-9]+/g替换) - 左侧目录生成后,点击跳转用
document.getElementById(id).scrollIntoView({ behavior: 'smooth', block: 'start' }) - 监听滚动时用
IntersectionObserver判断哪个章节进入视口,动态高亮对应目录项 - 必须设置
html { scroll-behavior: smooth; }和body { scroll-margin-top: 64px; }(数值匹配 header 高度),否则锚点滚动会卡在顶部被遮挡
怎么让文档支持离线缓存与版本切换
不依赖 Service Worker 复杂生命周期,优先用 localStorage 缓存内容,配合简单版本标识即可满足多数场景:
立即学习“前端免费学习笔记(深入)”;
- 每次通过
fetch()加载文档源(如docs/v1.2/api.md)成功后,把响应文本连同时间戳、版本号一起存入localStorage.setItem('docs-v1.2', JSON.stringify({ content, timestamp, version })) - 页面加载时先查
localStorage,命中且未过期(比如 24 小时内),直接渲染;否则发起网络请求并更新缓存 - 版本切换按钮只需改变 URL path 参数(如
?v=v1.1),JS 解析后加载对应路径,无需重刷页面 - 注意:
localStorage容量约 5–10MB,适合中小型文档;超大文件建议改用Cache API配合简单 SW 脚本
为什么拖拽上传示例代码反而容易出问题
文档系统里加拖拽功能看似提升体验,实则引入兼容性、权限和 UX 三重风险:
- Firefox 不支持对
input[type="file"]元素触发dataTransfer.items访问,导致拖入后读不到文件 - 用户拖进来的可能是任意格式(.zip、.pdf),而文档系统只预期 .md 或 .json,不做校验就报错或静默失败
- 拖拽区域若覆盖整个文档容器,会干扰正常滚动和选中文本,尤其在触屏设备上误触发频繁
- 真正轻量的做法是:保留一个显眼的
<label for="file-input">上传文档</label>,搭配隐藏的<input type="file" id="file-input" accept=".md,.json">,稳定又可控
最常被忽略的是:文档系统不是应用,它的核心价值在于“被人快速看懂”。所有交互功能都该服务于这个目标——加一个折叠代码块,比硬塞进一个实时协作编辑器更有意义。



















