fix(viewer): 环回瞬时回位强制重排——同帧恢复过渡导致可见反向长滚

真浏览器样式计算时过渡仍在,回跳变成动画;强制 offsetWidth 重排 +
双 rAF 确保无过渡状态先绘制一帧(测试假时钟下掩盖的根因)。

Co-Authored-By: Claude Code <noreply@anthropic.com>
This commit is contained in:
浅念
2026-09-29 15:00:50 +08:00
parent 38b913b429
commit 8c47a88c79
+12 -2
View File
@@ -34,6 +34,8 @@ const SLIDE_MS = 450;
const trackPos = ref(1);
/** 瞬时回位期间关闭过渡(transform 跳转不产生动画)。 */
const noTransition = ref(false);
/** 轨道元素(snapBack 强制重排用)。 */
const trackEl = ref<HTMLElement | null>(null);
let snapTimer: ReturnType<typeof setTimeout> | undefined;
/** 轨道帧序列:{ ad, real }——real 为真实 index,克隆帧为 null。 */
@@ -57,9 +59,16 @@ function clearSnapTimer(): void {
async function snapBack(): Promise<void> {
noTransition.value = true;
trackPos.value = current.value + 1;
// 同帧应用「关过渡 + 新 transform」,下一拍恢复过渡(transform 已就位不触发)。
await nextTick();
noTransition.value = false;
// 强制重排 + 双 rAF:确保「无过渡 + 新 transform」先完成一次绘制,再恢复
// 过渡。若在同一帧内直接恢复(浏览器样式计算时过渡仍在),回跳会变成可见
// 的反向长滚(2026-09-29 线上反馈根因;测试假时钟下恰好掩盖)。
void trackEl.value?.offsetWidth;
requestAnimationFrame(() => {
requestAnimationFrame(() => {
noTransition.value = false;
});
});
}
/** 移动到真实 index(圆点/滑动/自动轮播共用):环回走克隆位 + 到位后回跳。 */
@@ -170,6 +179,7 @@ function openAd(ad: PublicAd): void {
令环回也是单帧宽自然滑入(到位后关过渡瞬时回位,见 script);仅活跃
真实帧可聚焦;错误上报只看活跃帧。 -->
<div
ref="trackEl"
class="ad-slides" :class="{ 'no-transition': noTransition }"
:style="{ transform: `translateX(-${trackPos * 100}%)` }"
>