进度条要由真实进度驱动
一、需求本身有四个约束
- 覆盖范围要完整 —— 侧边栏的品牌栏与主 nav 是两个独立元素(只是恰好都高 60px、都有底边框),只给主 nav 挂动画,左边自然是空的。
- 要一直从左到右扫过,不是闪烁。
- 扫到尽头时刚好加载完成 —— 与加载状态同步。
- 到尽头后停在满格,等加载完才消失。
二、坏掉的推进逻辑(根因)
const dt = now - last; // ≈ 16ms(两帧间隔)
last = now; // 每帧都重置
if (dt >= TICK_MS) { // 16 >= 60 → 永远 false
setProgress(...)
}
两个叠加错误:
dt单帧只有 ~16ms,永远达不到 60ms,setProgress在绝大多数帧里根本不执行;last = now每帧重置,dt永远累积不起来。
真正把进度推到 100% 的是 pathname effect 里的一次性赋值。于是视觉上就是 0 → 100%,中间没有任何帧 —— 这就是"固定时间快速闪过、与加载不同步"。
正确做法:按经过时间做连续计算(elapsed / duration),而不是用帧间隔做定时判定。
三、验证时的采样陷阱
用 MutationObserver 观察 style 变化来采样进度,只拿到 4 个点 —— 因为 rAF 每帧写入相同的值会被浏览器合并,只有真正变化的属性才触发。要验证中间帧,得连续读取,不能依赖观察器。
相关
- 判据要用真值而非代理 —— 本条是该 synthesis 的一处实例:拿「帧间隔/循环动画」当真实进度
- 流式更新要合并字段而非替换对象(同一天的前端状态更新问题)
- 样式丢失先核对类名再怀疑缓存与权限(先确认元素是不是同一个)
- 高频手势缩放不要走React状态(同类:高频更新不该驱动框架状态)