执子念

前端文件预览回归实战:十万行 Excel、OFD 闪烁与 PDF 缩放跳页

最近项目页面进入了 2K Star 的显示节点。对维护者来说,这更像一次回头检查:新增关注能说明项目被看见,却不能证明一个 100,545 行的工作簿不会卡、OFD 不会闪、PDF 缩放不会跳页。

真正有价值的是,这三个问题都由真实使用者留下了可复现证据,并最终进入代码和浏览器回归。本文把修复过程整理成一套可复用的排查方法。

三条真实反馈对应三种不同的根因

案例一:自动列宽把十万行重新扫描了一遍

问题样例为 38,732,752 字节、100,545 行 x 20 列。表格解析本身并不是唯一成本:没有显式列宽时,自动列宽还会扫描单元格内容,以估算每一列的显示宽度。

如果工作量随着总行数无限增长,优化 Worker 或虚拟滚动也无法消除首屏前的长任务。最终方案是给列宽测量设置固定预算,并把样本均匀分布到工作表前、中、后部。

const AUTO_FIT_MAX_SAMPLE_CELLS = 100_000
const AUTO_FIT_MAX_SAMPLE_WINDOWS = 8
const AUTO_FIT_MAX_ROWS_PER_WINDOW = 128

const rowsPerWindow = Math.max(1, Math.min(
  AUTO_FIT_MAX_ROWS_PER_WINDOW,
  Math.floor(
    AUTO_FIT_MAX_SAMPLE_CELLS /
    totalColumns /
    AUTO_FIT_MAX_SAMPLE_WINDOWS
  )
))

小表仍然全量测量;大表的测量成本则被限制在明确上限内。多个窗口的测量结果按列取最大宽度,兼顾标题区、正文区和尾部数据。

这类性能问题的通用检查项是:

  • 是否重复展开压缩包中的大型 XML;

  • 是否为了样式、图表或列宽再次遍历全部单元格;

  • Worker 结束后,主线程是否又做了一次同量级转换;

  • 虚拟列表是否只减少 DOM,却没有减少前置计算。

案例二:初始 transform 被当成动画播放

OFD 内容出现后从右侧闪入,并不是文档解析失败,而是新插入的页面从 transform: none 过渡到居中缩放状态。

正确的状态划分是:初次布局立即提交;只有用户主动缩放时才开启动画。

.ofd-page {
  transition: none;
}

.ofd-page.ofd-page--zoom-ready {
  transition: transform 160ms ease;
}

@media (prefers-reduced-motion: reduce) {
  .ofd-page.ofd-page--zoom-ready { transition: none; }
}

页面完成初次测量和定位后,再添加 ofd-page--zoom-ready。回归要覆盖从其他格式切到 OFD,以及连续切换两个 OFD;只刷新后打开一次,可能看不到生命周期问题。

案例三:PDF 缩放不能只恢复绝对滚动值

PDF 页面缩放后高度发生变化。保存旧 scrollTop 再原样写回,会让视口落在另一页或当前页的不同位置。

更稳定的锚点是“页码 + 页内比例”:

interface PdfPageAnchor {
  page: number
  inPageRatio: number
}

function restoreAnchor(anchor: PdfPageAnchor) {
  const page = getPageElement(anchor.page)
  const pageTop = getPageTop(page)
  container.scrollTop = pageTop + anchor.inPageRatio * page.offsetHeight
}

布局不是同步完成的,因此实现还需要在后续绘制帧继续确认锚点;用户一旦主动滚动,则立即取消待恢复任务,不能和用户争夺滚动位置。

第一次修复仅覆盖顶部工具栏,反馈者复测后指出底部入口仍会跳。最终回归矩阵加入顶部、底部、连续放大和反向缩小,避免同一能力因入口不同而走两套逻辑。

看到卡、闪、跳时先问四个定位问题

怎样把修复变成回归

对文件预览,验收标准不能只写“打开成功”。建议至少记录:

  1. 输入文件哈希、大小、页数或行列规模;

  2. 最短操作路径和浏览器版本;

  3. 需要观察的性能、布局或交互状态;

  4. 正向、反向、重复和多入口操作;

  5. 控制台错误、网络资源和最终页面状态。

反馈进入工程系统需要走完真实文件、稳定复现、修复和自动回归

边界说明

浏览器本地预览并不适合所有文件。极端大文件、严格分页一致、复杂宏与嵌入对象、专业 CAD 审图等场景,服务端转码或桌面工具通常更稳妥。File Viewer 也是只读预览器,不承担 Office 或 CAD 编辑职责。

截至 2026-08-12,公开版本为 2.2.8。本文对应的实现与回归脚本可在 File Viewer 查看。2K 只是页面的一次显示节点,真正能长期留下来的仍然是这些失败样例和回归用例。

posted on 2026-08-12 16:48  执子念  阅读(13)  评论(0)    收藏  举报

导航