摘要
内联 PDF 预览在滚动浏览长篇主题时,其滚动位置(返回第 1 页)会持续重置。这发生的原因是,当帖子滚动出视图时,PDF 嵌入被销毁并重新插入,这很可能是由于 Discourse 的帖子流回收/虚拟化机制导致的。
这会影响所有浏览器、所有 PDF,即使禁用所有插件和主题也会发生。
重现步骤
- 创建一个带有 PDF 附件的主题。
- 确保“内联 PDF 预览”组件处于激活状态。
- 向下滚动主题,直到包含 PDF 的帖子离开视口。
- 滚动回同一个 PDF 预览。
- 结果:
- PDF 从头开始重新加载。
- 预览的滚动位置丢失。
- PDF 像刚加载时一样被重新渲染。
没有发生对 PDF 的网络请求,这表明 DOM 节点在本地被移除并重新创建。
预期行为
- PDF 预览应保持其滚动位置,不应仅仅因为滚动主题而重新加载。
- 其他嵌入式内容(图像、视频、Onebox)在滚动时不会重置状态;PDF 预览应保持一致的行为。
实际行为
- 一旦帖子超出可见范围,Discourse 就会卸载 DOM 节点。
- 当帖子滚动回视图时,嵌入被重建。
- 这会强制浏览器的原生 PDF 渲染器从第 1 页重新开始。
- 每当帖子离开视口(向上或向下)时,都会发生这种情况。
环境
- 在所有测试过的浏览器中都会发生:Chrome、Firefox、Safari、Edge
- 禁用所有插件时发生(安全模式)
- 禁用所有主题组件时发生
- 使用多个不同大小和格式的 PDF 文件时发生
- 在 Discourse (tests-passed) 最新分支上发生(截至发布之日)
技术说明
Discourse 似乎正在作为流虚拟化的一部分卸载屏幕外的帖子组件。由于 PDF 预览使用简单的 \<embed\> / \<iframe\>,它没有持久化机制,因此每当发生以下情况时,它就会完全重置:
- 触发
willDestroyElement() - 帖子容器被重新渲染
- DOM 节点在重新进入视口时被重建
这对于 PDF 来说是独有的,因为浏览器原生的 PDF 查看器在 DOM 重建过程中不会保留滚动状态。这使得带有 PDF 的长篇主题阅读起来很令人沮丧,特别是对于多页附件。
所需的解决方案
- 防止“内联 PDF 预览”组件在帖子回收期间被销毁,或者
- 提供一种方式让插件/主题组件声明“持久化状态”,以便 Discourse 不会卸载它们,或者
- 暴露一个站点设置,为包含内联 PDF 查看器的帖子禁用帖子流回收。
即使是部分修复——例如,跳过对包含 PDF 嵌入的帖子的回收——也能解决问题。
附加背景
这不是一次性的环境问题:在干净的测试构建、多种浏览器和跨 PDF 的情况下都可靠地重现了此问题。
Meta(论坛)上没有描述此行为的主题,因此这可能是流虚拟化改进带来的未报告的回归或意外后果。