# Design

# 根因

现有 enhanceFollowupAccordionsPage.getPageData() 和静态文档解密完成后同步执行。它会对页面全部 .custom-block.followup 创建新节点、复制回答段落并替换列表;超长面经的 1218 张卡在一个任务内完成,阻塞事件循环。

# 方案

  • 首次扫描只给待处理卡片标记 data-followup-state="queued",避免页面状态机重复入队。
  • 使用 requestIdleCallback 调度;不支持时回退 setTimeout(0)
  • 每个切片最多转换 6 张卡,并在空闲预算不足时立即让出主线程。
  • 单卡异常时标记为跳过并保留原列表,避免一个脏结构阻断后续卡片。
  • 转换完成写入 data-followup-state="done";重复调用幂等。
  • 解密后的超长 HTML 按顶层块节点聚合成约 48KB 的安全分块,首块立即展示;仅在真实滚动使末尾哨兵接近视口,或用户点击加载按钮时,才在空闲切片追加两块。注册监听时不主动检查,避免初始布局阶段误判后连续灌入全文。
  • 每次只对新增分块运行追问增强,避免随正文增长反复全页扫描。
  • 当路由 hash 指向尚未渲染的标题时,在已解密但尚未挂载的分块字符串中直接查找目标 id,只挂载命中的约 80KB 分块并 scrollIntoView。深锚点不从文章开头逐块 patch 到目标,避免第 309 题一类定位重新创建十几万节点。
  • 定位时动态读取固定 Navbar 的底边,在标题上方额外保留 24px;标题 CSS 同时设置 scroll-margin-top,覆盖原生 hash 和无脚本降级,避免标题滚到 top: 0 后被导航栏遮挡。
  • 深锚点分块从目标标题的顶层 <h*> 边界开始截取,目标上方不再包含会被追问增强改变高度的旧题。分块挂载和两次位置校正期间保持 visibility: hidden,400ms 稳定后同一帧显示并最终对齐,避免“先出现、再跳、再微调”的闪烁。

# 兼容性

Vue 2、VuePress 1 和 SSR 均保持兼容;服务端不访问 document,原始列表仍是首屏与无 JavaScript 降级内容。

# 同步流水线约束

sync-interview-next-docs.mjs 生成静态文档后必须立即执行强制加密。任何 { html, headers } 明文产物都会重新进入 SSR 与公共 JS,同时造成内容泄露和超长页刷新卡死;加密失败时同步命令必须非零退出。

webapp
公众号
开发者导航
切换夜间模式
折叠侧边栏
收起全部